Code Monkey home page Code Monkey logo

spotify-web-api-node's Introduction

Spotify Web API Node

Tests Coverage Status npm bundle size (minified + gzip)

This is a universal wrapper/client for the Spotify Web API that runs on Node.JS and the browser, using browserify/webpack/rollup. A list of selected wrappers for different languages and environments is available at the Developer site's Libraries page.

Project owners are thelinmichael and JMPerez, with help from a lot of awesome contributors.

Version 5

⚠️ Since the last release (4.0.0, released over year ago) a lot of new functionality has been added by a lot of different contributors. Thank you. In order to implement some of the feature requests, some breaking changes had to be made. A list of them, along with a list of the new functionality, can be found in the CHANGELOG.

Table of contents

Features

The library includes helper functions to do the following:

Fetch music metadata

  • Albums, artists, and tracks
  • Audio features and analysis for tracks
  • Albums for a specific artist
  • Top tracks for a specific artist
  • Artists similar to a specific artist

Profiles

  • User's emails, product type, display name, birthdate, image

Search

  • Albums, artists, tracks, and playlists

Playlist manipulation

  • Get a user's playlists
  • Create playlists
  • Change playlist details
  • Add tracks to a playlist
  • Remove tracks from a playlist
  • Replace tracks in a playlist
  • Reorder tracks in a playlist

Your Music library

  • Add, remove, and get tracks and albums that are in the signed in user's Your Music library
  • Check if a track or album is in the signed in user's Your Music library

Personalization

  • Get a user’s top artists and tracks based on calculated affinity

Browse

  • Get New Releases
  • Get Featured Playlists
  • Get a List of Categories
  • Get a Category
  • Get a Category's Playlists
  • Get recommendations based on seeds
  • Get available genre seeds

Player

  • Get a User's Available Devices
  • Get Information About The User's Current Playback State
  • Get Current User's Recently Played Tracks
  • Get the User's Currently Playing Track
  • Pause a User's Playback
  • Seek To Position In Currently Playing Track
  • Set Repeat Mode On User’s Playback
  • Set Volume For User's Playback
  • Skip User’s Playback To Next Track
  • Skip User’s Playback To Previous Track
  • Start/Resume a User's Playback
  • Toggle Shuffle For User’s Playback
  • Transfer a User's Playback

Follow

  • Follow and unfollow users
  • Follow and unfollow artists
  • Check if the logged in user follows a user or artist
  • Follow a playlist
  • Unfollow a playlist
  • Get followed artists
  • Check if users are following a Playlist

Player

  • Add an Item to the User's Playback Queue
  • Get a user's available devices
  • Get information about the user's current playback
  • Get current user’s recently played tracks
  • Transfer a user's playback
  • Resume a user's playback
  • Skip a user's playback to next track
  • Skip a user's playback to previous track
  • Set a user's shuffle mode
  • Set a user's repeat mode
  • Set volume
  • Seek playback to a given position

Shows

Authentication

All methods require authentication, which can be done using these flows:

Dependencies

This project depends on superagent to make HTTP requests.

Installation

$ npm install spotify-web-api-node --save

Usage

First, instantiate the wrapper.

var SpotifyWebApi = require('spotify-web-api-node');

// credentials are optional
var spotifyApi = new SpotifyWebApi({
  clientId: 'fcecfc72172e4cd267473117a17cbd4d',
  clientSecret: 'a6338157c9bb5ac9c71924cb2940e1a7',
  redirectUri: 'http://www.example.com/callback'
});

If you've got an access token and want to use it for all calls, simply use the API object's set method. Handling credentials is described in detail in the Authorization section.

spotifyApi.setAccessToken('<your_access_token>');

Lastly, use the wrapper's helper methods to make the request to Spotify's Web API. The wrapper uses promises, so you need to provide a success callback as well as an error callback.

// Get Elvis' albums
spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then(
  function(data) {
    console.log('Artist albums', data.body);
  },
  function(err) {
    console.error(err);
  }
);

If you dont wan't to use promises, you can provide a callback method instead.

// Get Elvis' albums
spotifyApi.getArtistAlbums(
  '43ZHCT0cAZBISjO8DG9PnE',
  { limit: 10, offset: 20 },
  function(err, data) {
    if (err) {
      console.error('Something went wrong!');
    } else {
      console.log(data.body);
    }
  }
);

The functions that fetch data from the API also accept a JSON object with a set of options. For example, limit and offset can be used in functions that returns paginated results, such as search and retrieving an artist's albums.

Note that the options parameter is required if you're using a callback method., even if it's empty.

// Passing a callback - get Elvis' albums in range [20...29]
spotifyApi
  .getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE', { limit: 10, offset: 20 })
  .then(
    function(data) {
      console.log('Album information', data.body);
    },
    function(err) {
      console.error(err);
    }
  );

Responses and errors

This exposes the response headers, status code and body.

{
  "body" : {

  },
  "headers" : {

  },
  "statusCode" :
}

Errors have same fields, as well as a human readable message. This is especially useful since Spotify's Web API returns different types of error objects depending on the endpoint being called.

Example of a response

Retrieving a track's metadata in spotify-web-api-node version 1.4.0 and later:

{
  "body": {
    "name": "Golpe Maestro",
    "popularity": 42,
    "preview_url":
      "https://p.scdn.co/mp3-preview/4ac44a56e3a4b7b354c1273d7550bbad38c51f5d",
    "track_number": 1,
    "type": "track",
    "uri": "spotify:track:3Qm86XLflmIXVm1wcwkgDK"
  },
  "headers": {
    "date": "Fri, 27 Feb 2015 09:25:48 GMT",
    "content-type": "application/json; charset=utf-8",
    "cache-control": "public, max-age=7200"
  },
  "statusCode": 200
}

More examples

Below are examples for all helper functions. Longer examples of some requests can be found in the examples folder.

var SpotifyWebApi = require('spotify-web-api-node');

var spotifyApi = new SpotifyWebApi();

/**
 * Get metadata of tracks, albums, artists, shows, and episodes
 */

// Get album
spotifyApi.getAlbum('5U4W9E5WsYb2jUQWePT8Xm')
  .then(function(data) {
    console.log('Album information', data.body);
  }, function(err) {
    console.error(err);
  });

// Get multiple albums
spotifyApi.getAlbums(['5U4W9E5WsYb2jUQWePT8Xm', '3KyVcddATClQKIdtaap4bV'])
  .then(function(data) {
    console.log('Albums information', data.body);
  }, function(err) {
    console.error(err);
  });

// Get an artist
spotifyApi.getArtist('2hazSY4Ef3aB9ATXW7F5w3')
  .then(function(data) {
    console.log('Artist information', data.body);
  }, function(err) {
    console.error(err);
  });

// Get multiple artists
spotifyApi.getArtists(['2hazSY4Ef3aB9ATXW7F5w3', '6J6yx1t3nwIDyPXk5xa7O8'])
  .then(function(data) {
    console.log('Artists information', data.body);
  }, function(err) {
    console.error(err);
  });

// Get albums by a certain artist
spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE')
  .then(function(data) {
    console.log('Artist albums', data.body);
  }, function(err) {
    console.error(err);
  });

// Search tracks whose name, album or artist contains 'Love'
spotifyApi.searchTracks('Love')
  .then(function(data) {
    console.log('Search by "Love"', data.body);
  }, function(err) {
    console.error(err);
  });

// Search artists whose name contains 'Love'
spotifyApi.searchArtists('Love')
  .then(function(data) {
    console.log('Search artists by "Love"', data.body);
  }, function(err) {
    console.error(err);
  });

// Search tracks whose artist's name contains 'Love'
spotifyApi.searchTracks('artist:Love')
  .then(function(data) {
    console.log('Search tracks by "Love" in the artist name', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Search tracks whose artist's name contains 'Kendrick Lamar', and track name contains 'Alright'
spotifyApi.searchTracks('track:Alright artist:Kendrick Lamar')
  .then(function(data) {
    console.log('Search tracks by "Alright" in the track name and "Kendrick Lamar" in the artist name', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });


// Search playlists whose name or description contains 'workout'
spotifyApi.searchPlaylists('workout')
  .then(function(data) {
    console.log('Found playlists are', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get tracks in an album
spotifyApi.getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ', { limit : 5, offset : 1 })
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get an artist's top tracks
spotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy', 'GB')
  .then(function(data) {
    console.log(data.body);
    }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get artists related to an artist
spotifyApi.getArtistRelatedArtists('0qeei9KQnptjwb8MgkqEoy')
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    done(err);
  });

/* Get Audio Features for a Track */
spotifyApi.getAudioFeaturesForTrack('3Qm86XLflmIXVm1wcwkgDK')
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    done(err);
  });

/* Get Audio Analysis for a Track */
spotifyApi.getAudioAnalysisForTrack('3Qm86XLflmIXVm1wcwkgDK')
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    done(err);
  });

/* Get Audio Features for several tracks */
spotifyApi.getAudioFeaturesForTracks(['4iV5W9uYEdYUVa79Axb7Rh', '3Qm86XLflmIXVm1wcwkgDK'])
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    done(err);
  });


/*
 * User methods
 */

// Get a user
spotifyApi.getUser('petteralexis')
  .then(function(data) {
    console.log('Some information about this user', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get the authenticated user
spotifyApi.getMe()
  .then(function(data) {
    console.log('Some information about the authenticated user', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/*
 * Playlist methods
 */

// Get a playlist
spotifyApi.getPlaylist('5ieJqeLJjjI8iJWaxeBLuK')
  .then(function(data) {
    console.log('Some information about this playlist', data.body);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get a user's playlists
spotifyApi.getUserPlaylists('thelinmichael')
  .then(function(data) {
    console.log('Retrieved playlists', data.body);
  },function(err) {
    console.log('Something went wrong!', err);
  });

// Create a private playlist
spotifyApi.createPlaylist('My playlist', { 'description': 'My description', 'public': true })
  .then(function(data) {
    console.log('Created playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Add tracks to a playlist
spotifyApi.addTracksToPlaylist('5ieJqeLJjjI8iJWaxeBLuK', ["spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M"])
  .then(function(data) {
    console.log('Added tracks to playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Add tracks to a specific position in a playlist
spotifyApi.addTracksToPlaylist('5ieJqeLJjjI8iJWaxeBLuK', ["spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M"],
  {
    position : 5
  })
  .then(function(data) {
    console.log('Added tracks to playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Remove tracks from a playlist at a specific position
spotifyApi.removeTracksFromPlaylistByPosition('5ieJqeLJjjI8iJWaxeBLuK', [0, 2, 130], "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9")
  .then(function(data) {
    console.log('Tracks removed from playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Remove all occurrence of a track
var tracks = [{ uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh" }];
var playlistId = '5ieJqeLJjjI8iJWaxeBLuK';
var options = { snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9" };
spotifyApi.removeTracksFromPlaylist(playlistId, tracks, options)
  .then(function(data) {
    console.log('Tracks removed from playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Reorder the first two tracks in a playlist to the place before the track at the 10th position
var options = { "range_length" : 2 };
spotifyApi.reorderTracksInPlaylist('5ieJqeLJjjI8iJWaxeBLuK', 0, 10, options)
  .then(function(data) {
    console.log('Tracks reordered in playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Change playlist details
spotifyApi.changePlaylistDetails('5ieJqeLJjjI8iJWaxeBLuK',
  {
    name: 'This is a new name for my Cool Playlist, and will become private',
    'public' : false
  }).then(function(data) {
     console.log('Playlist is now private!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Upload a custom playlist cover image
spotifyApi.uploadCustomPlaylistCoverImage('5ieJqeLJjjI8iJWaxeBLuK','longbase64uri')
  .then(function(data) {
     console.log('Playlsit cover image uploaded!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Follow a playlist (privately)
spotifyApi.followPlaylist('5ieJqeLJjjI8iJWaxeBLuK',
  {
    'public' : false
  }).then(function(data) {
     console.log('Playlist successfully followed privately!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Unfollow a playlist
spotifyApi.unfollowPlaylist('5ieJqeLJjjI8iJWaxeBLuK')
  .then(function(data) {
     console.log('Playlist successfully unfollowed!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Check if Users are following a Playlist
spotifyApi.areFollowingPlaylist('5ieJqeLJjjI8iJWaxeBLuK', ['thelinmichael', 'ella'])
 .then(function(data) {
    data.body.forEach(function(isFollowing) {
      console.log("User is following: " + isFollowing);
    });
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/*
 * Following Users and Artists methods
 */

/* Get followed artists */
spotifyApi.getFollowedArtists({ limit : 1 })
  .then(function(data) {
      // 'This user is following 1051 artists!'
     console.log('This user is following ', data.body.artists.total, ' artists!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Follow a user */
spotifyApi.followUsers(['thelinmichael'])
  .then(function(data) {
     console.log(data);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Follow an artist */
spotifyApi.followArtists(['2hazSY4Ef3aB9ATXW7F5w3', '6J6yx1t3nwIDyPXk5xa7O8'])
  .then(function(data) {
     console.log(data);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Unfollow a user */
spotifyApi.unfollowUsers(['thelinmichael'])
  .then(function(data) {
     console.log(data);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Unfollow an artist */
spotifyApi.unfollowArtists(['2hazSY4Ef3aB9ATXW7F5w3', '6J6yx1t3nwIDyPXk5xa7O8'])
  .then(function(data) {
     console.log(data);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Check if a user is following a user */
let usersId = ['thelinmichael'];

spotifyApi.isFollowingUsers(usersId)
  .then(function(data) {
    let isFollowing = data.body;

    for (let index = 0; index < usersId.length; index++) {
      console.log(usersId[index] + ':' + isFollowing[index])
    }
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Check if a user is following an artist */
let artistsId = ['6mfK6Q2tzLMEchAr0e9Uzu', '4DYFVNKZ1uixa6SQTvzQwJ'];

spotifyApi.isFollowingArtists(artistsId)
  .then(function(data) {
    let isFollowing = data.body;

    for (let index = 0; index < artistsId.length; index++) {
      console.log(artistsId[index] + ':' + isFollowing[index])
    }
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/*
 * Your Music library methods
 */

/* Tracks */

// Get tracks in the signed in user's Your Music library
spotifyApi.getMySavedTracks({
    limit : 2,
    offset: 1
  })
  .then(function(data) {
    console.log('Done!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });


// Check if tracks are in the signed in user's Your Music library
spotifyApi.containsMySavedTracks(["5ybJm6GczjQOgTqmJ0BomP"])
  .then(function(data) {

    // An array is returned, where the first element corresponds to the first track ID in the query
    var trackIsInYourMusic = data.body[0];

    if (trackIsInYourMusic) {
      console.log('Track was found in the user\'s Your Music library');
    } else {
      console.log('Track was not found.');
    }
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Remove tracks from the signed in user's Your Music library
spotifyApi.removeFromMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"])
  .then(function(data) {
    console.log('Removed!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });
});

// Add tracks to the signed in user's Your Music library
spotifyApi.addToMySavedTracks(["3VNWq8rTnQG6fM1eldSpZ0"])
  .then(function(data) {
    console.log('Added track!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });
});

/* Albums */

// Get albums in the signed in user's Your Music library
spotifyApi.getMySavedAlbums({
    limit : 1,
    offset: 0
  })
  .then(function(data) {
    // Output items
    console.log(data.body.items);
  }, function(err) {
    console.log('Something went wrong!', err);
  });


// Check if albums are in the signed in user's Your Music library
spotifyApi.containsMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"])
  .then(function(data) {

    // An array is returned, where the first element corresponds to the first album ID in the query
    var albumIsInYourMusic = data.body[0];

    if (albumIsInYourMusic) {
      console.log('Album was found in the user\'s Your Music library');
    } else {
      console.log('Album was not found.');
    }
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Remove albums from the signed in user's Your Music library
spotifyApi.removeFromMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"])
  .then(function(data) {
    console.log('Removed!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });
});

// Add albums to the signed in user's Your Music library
spotifyApi.addToMySavedAlbums(["1H8AHEB8VSE8irHViGOIrF"])
  .then(function(data) {
    console.log('Added album!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });
});


/*
 * Browse methods
 */

  // Retrieve new releases
spotifyApi.getNewReleases({ limit : 5, offset: 0, country: 'SE' })
  .then(function(data) {
    console.log(data.body);
      done();
    }, function(err) {
       console.log("Something went wrong!", err);
    });
  });

//  Retrieve featured playlists
spotifyApi.getFeaturedPlaylists({ limit : 3, offset: 1, country: 'SE', locale: 'sv_SE', timestamp:'2014-10-23T09:00:00' })
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    console.log("Something went wrong!", err);
  });

// Get a List of Categories
spotifyApi.getCategories({
      limit : 5,
      offset: 0,
      country: 'SE',
      locale: 'sv_SE'
  })
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    console.log("Something went wrong!", err);
  });

// Get a Category (in Sweden)
spotifyApi.getCategory('party', {
      country: 'SE',
      locale: 'sv_SE'
  })
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    console.log("Something went wrong!", err);
  });

// Get Playlists for a Category (Party in Brazil)
spotifyApi.getPlaylistsForCategory('party', {
      country: 'BR',
      limit : 2,
      offset : 0
    })
  .then(function(data) {
    console.log(data.body);
  }, function(err) {
    console.log("Something went wrong!", err);
  });

// Get Recommendations Based on Seeds
spotifyApi.getRecommendations({
      min_energy: 0.4,
      seed_artists: ['6mfK6Q2tzLMEchAr0e9Uzu', '4DYFVNKZ1uixa6SQTvzQwJ'],
      min_popularity: 50
    })
  .then(function(data) {
    let recommendations = data.body;
    console.log(recommendations);
  }, function(err) {
    console.log("Something went wrong!", err);
  });

// Get available genre seeds
spotifyApi.getAvailableGenreSeeds()
  .then(function(data) {
    let genreSeeds = data.body;
    console.log(genreSeeds);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Player */

// Add an Item to the User's Playback Queue
// TBD

// Get a User's Available Devices
spotifyApi.getMyDevices()
  .then(function(data) {
    let availableDevices = data.body.devices;
    console.log(availableDevices);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get Information About The User's Current Playback State
spotifyApi.getMyCurrentPlaybackState()
  .then(function(data) {
    // Output items
    if (data.body && data.body.is_playing) {
      console.log("User is currently playing something!");
    } else {
      console.log("User is not playing anything, or doing so in private.");
    }
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get Current User's Recently Played Tracks
spotifyApi.getMyRecentlyPlayedTracks({
  limit : 20
}).then(function(data) {
    // Output items
    console.log("Your 20 most recently played tracks are:");
    data.body.items.forEach(item => console.log(item.track));
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Get the User's Currently Playing Track 
spotifyApi.getMyCurrentPlayingTrack()
  .then(function(data) {
    console.log('Now playing: ' + data.body.item.name);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

// Pause a User's Playback
spotifyApi.pause()
  .then(function() {
    console.log('Playback paused');
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Seek To Position In Currently Playing Track
spotifyApi.seek(positionMs)
  .then(function() {
    console.log('Seek to ' + positionMs);
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Set Repeat Mode On User’s Playback
spotifyApi.setRepeat('track')
  .then(function () {
    console.log('Repeat track.');
    }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Set Volume For User's Playback
spotifyApi.setVolume(50)
  .then(function () {
    console.log('Setting volume to 50.');
    }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Skip User’s Playback To Next Track
spotifyApi.skipToNext()
  .then(function() {
    console.log('Skip to next');
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Skip User’s Playback To Previous Track 
spotifyApi.skipToPrevious()
  .then(function() {
    console.log('Skip to previous');
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Start/Resume a User's Playback 
spotifyApi.play()
  .then(function() {
    console.log('Playback started');
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Toggle Shuffle For User’s Playback
spotifyApi.setShuffle(true)
  .then(function() {
    console.log('Shuffle is on.');
  }, function  (err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });

// Transfer a User's Playback
spotifyApi.transferMyPlayback(deviceIds)
  .then(function() {
    console.log('Transfering playback to ' + deviceIds);
  }, function(err) {
    //if the user making the request is non-premium, a 403 FORBIDDEN response code will be returned
    console.log('Something went wrong!', err);
  });


/**
 * Personalization Endpoints
 */

/* Get a User’s Top Artists*/
spotifyApi.getMyTopArtists()
  .then(function(data) {
    let topArtists = data.body.items;
    console.log(topArtists);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

/* Get a User’s Top Tracks*/
spotifyApi.getMyTopTracks()
  .then(function(data) {
    let topTracks = data.body.items;
    console.log(topTracks);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

Chaining calls

// track detail information for album tracks
spotifyApi
  .getAlbum('5U4W9E5WsYb2jUQWePT8Xm')
  .then(function(data) {
    return data.body.tracks.map(function(t) {
      return t.id;
    });
  })
  .then(function(trackIds) {
    return spotifyApi.getTracks(trackIds);
  })
  .then(function(data) {
    console.log(data.body);
  })
  .catch(function(error) {
    console.error(error);
  });

// album detail for the first 10 Elvis' albums
spotifyApi
  .getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE', { limit: 10 })
  .then(function(data) {
    return data.body.albums.map(function(a) {
      return a.id;
    });
  })
  .then(function(albums) {
    return spotifyApi.getAlbums(albums);
  })
  .then(function(data) {
    console.log(data.body);
  });

Authorization

Supplying an access token is required for all requests to the Spotify API. This wrapper supports three authorization flows - The Authorization Code flow (signed by a user), the Client Credentials flow (application authentication - the user isn't involved), and the Implicit Grant Flow (For completely clientside applications). See Spotify's Authorization guide for detailed information on these flows.

Important: If you are writing a universal/isomorphic web app using this library, you will not be able to use methods that send a client secret to the Spotify authorization service. Client secrets should be kept server-side and not exposed to client browsers. Never include your client secret in the public JS served to the browser.

The first thing you need to do is to create an application. A step-by-step tutorial is offered by Spotify in this tutorial.

Authorization code flow

With the application created and its redirect URI set, the only thing necessary for the application to retrieve an authorization code is the user's permission. Which permissions you're able to ask for is documented in Spotify's Using Scopes section.

In order to get permissions, you need to direct the user to Spotify's Accounts service. Generate the URL by using the wrapper's authorization URL method.

var scopes = ['user-read-private', 'user-read-email'],
  redirectUri = 'https://example.com/callback',
  clientId = '5fe01282e44241328a84e7c5cc169165',
  state = 'some-state-of-my-choice';

// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.
var spotifyApi = new SpotifyWebApi({
  redirectUri: redirectUri,
  clientId: clientId
});

// Create the authorization URL
var authorizeURL = spotifyApi.createAuthorizeURL(scopes, state);

// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choice
console.log(authorizeURL);

The example below uses a hardcoded authorization code, retrieved from the Accounts service as described above.

var credentials = {
  clientId: 'someClientId',
  clientSecret: 'someClientSecret',
  redirectUri: 'http://www.michaelthelin.se/test-callback'
};

var spotifyApi = new SpotifyWebApi(credentials);

// The code that's returned as a query parameter to the redirect URI
var code = 'MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';

// Retrieve an access token and a refresh token
spotifyApi.authorizationCodeGrant(code).then(
  function(data) {
    console.log('The token expires in ' + data.body['expires_in']);
    console.log('The access token is ' + data.body['access_token']);
    console.log('The refresh token is ' + data.body['refresh_token']);

    // Set the access token on the API object to use it in later calls
    spotifyApi.setAccessToken(data.body['access_token']);
    spotifyApi.setRefreshToken(data.body['refresh_token']);
  },
  function(err) {
    console.log('Something went wrong!', err);
  }
);

Since the access token was set on the API object in the previous success callback, it's going to be used in future calls. As it was retrieved using the Authorization Code flow, it can also be refreshed.

// clientId, clientSecret and refreshToken has been set on the api object previous to this call.
spotifyApi.refreshAccessToken().then(
  function(data) {
    console.log('The access token has been refreshed!');

    // Save the access token so that it's used in future calls
    spotifyApi.setAccessToken(data.body['access_token']);
  },
  function(err) {
    console.log('Could not refresh access token', err);
  }
);

Client Credential flow

The Client Credential flow doesn't require the user to give permissions, so it's suitable for requests where the application just needs to authenticate itself. This is the case with for example retrieving a playlist. However, note that the access token cannot be refreshed, and that it isn't connected to a specific user.

var clientId = 'someClientId',
  clientSecret = 'someClientSecret';

// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
  clientId: clientId,
  clientSecret: clientSecret
});

// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
  function(data) {
    console.log('The access token expires in ' + data.body['expires_in']);
    console.log('The access token is ' + data.body['access_token']);

    // Save the access token so that it's used in future calls
    spotifyApi.setAccessToken(data.body['access_token']);
  },
  function(err) {
    console.log('Something went wrong when retrieving an access token', err);
  }
);

Implicit Grant flow

The Implicit Grant can be used to allow users to login to your completely client-side application. This method still requires a registered application, but won't expose your client secret. This method of authentication won't return any refresh tokens, so you will need to fully reauthenticate the user everytime a token expires.

var scopes = ['user-read-private', 'user-read-email'],
  redirectUri = 'https://example.com/callback',
  clientId = '5fe01282e44241328a84e7c5cc169165',
  state = 'some-state-of-my-choice',
  showDialog = true,
  responseType = 'token';

// Setting credentials can be done in the wrapper's constructor, or using the API object's setters.
var spotifyApi = new SpotifyWebApi({
  redirectUri: redirectUri,
  clientId: clientId
});

// Create the authorization URL
var authorizeURL = spotifyApi.createAuthorizeURL(
  scopes,
  state,
  showDialog,
  responseType
);

// https://accounts.spotify.com/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=token&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choice&show_dialog=true
console.log(authorizeURL);

When the client returns, it will have a token we can directly pass to the library:

// The code that's returned as a hash fragment query string parameter to the redirect URI
var code = 'MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';
var credentials = {
  clientId: 'someClientId',
  clientSecret: 'someClientSecret',
  //Either here
  accessToken: code
};

var spotifyApi = new SpotifyWebApi(credentials);

//Or with a method
spotifyApi.setAccessToken(code);

Setting credentials

Credentials are either set when constructing the API object or set after the object has been created using setters. They can be set all at once or one at a time.

Using setters, getters and resetters.

// Use setters to set all credentials one by one
var spotifyApi = new SpotifyWebApi();
spotifyApi.setAccessToken('myAccessToken');
spotifyApi.setRefreshToken('myRefreshToken');
spotifyApi.setRedirectURI('http://www.example.com/test-callback');
spotifyApi.setClientId('myOwnClientId');
spotifyApi.setClientSecret('someSuperSecretString');

// Set all credentials at the same time
spotifyApi.setCredentials({
  accessToken: 'myAccessToken',
  refreshToken: 'myRefreshToken',
  redirectUri: 'http://www.example.com/test-callback',
  'clientId ': 'myClientId',
  clientSecret: 'myClientSecret'
});

// Get the credentials one by one
console.log('The access token is ' + spotifyApi.getAccessToken());
console.log('The refresh token is ' + spotifyApi.getRefreshToken());
console.log('The redirectURI is ' + spotifyApi.getRedirectURI());
console.log('The client ID is ' + spotifyApi.getClientId());
console.log('The client secret is ' + spotifyApi.getClientSecret());

// Get all credentials
console.log('The credentials are ' + spotifyApi.getCredentials());

// Reset the credentials
spotifyApi.resetAccessToken();
spotifyApi.resetRefreshToken();
spotifyApi.resetRedirectURI();
spotifyApi.resetClientId();
spotifyApi.resetClientSecret();
spotifyApi.resetCode();

// Reset all credentials at the same time
spotifyApi.resetCredentials();

Using the constructor.

// Set necessary parts of the credentials on the constructor
var spotifyApi = new SpotifyWebApi({
  clientId: 'myClientId',
  clientSecret: 'myClientSecret'
});

// Get an access token and 'save' it using a setter
spotifyApi.clientCredentialsGrant().then(
  function(data) {
    console.log('The access token is ' + data.body['access_token']);
    spotifyApi.setAccessToken(data.body['access_token']);
  },
  function(err) {
    console.log('Something went wrong!', err);
  }
);
// Set the credentials when making the request
var spotifyApi = new SpotifyWebApi({
  accessToken: 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'
});

// Do search using the access token
spotifyApi.searchTracks('artist:Love').then(
  function(data) {
    console.log(data.body);
  },
  function(err) {
    console.log('Something went wrong!', err);
  }
);
// Set the credentials when making the request
var spotifyApi = new SpotifyWebApi({
  accessToken: 'njd9wng4d0ycwnn3g4d1jm30yig4d27iom5lg4d3'
});

// Get tracks in a playlist
api
  .getPlaylistTracks('3ktAYNcRHpazJ9qecm3ptn', {
    offset: 1,
    limit: 5,
    fields: 'items'
  })
  .then(
    function(data) {
      console.log('The playlist contains these tracks', data.body);
    },
    function(err) {
      console.log('Something went wrong!', err);
    }
  );

Development

See something you think can be improved? Open an issue or clone the project and send a pull request with your changes.

Running tests

You can run the unit tests executing npm test and get a test coverage report running npm test -- --coverage.

spotify-web-api-node's People

Contributors

ajhaupt7 avatar ashtonmeuser avatar brodin avatar cazwazacz avatar dalerasrorov avatar dandv avatar danguilherme avatar dolcalmi avatar dustinblackman avatar gaganza avatar hughrawlinson avatar jeremyboles avatar jgranstrom avatar jmperez avatar josemco avatar kei-kinoshita avatar konstantinjdobler avatar krishorowitz avatar leecaleb avatar louiswilliams avatar madeddie avatar marinacrachi avatar matiassingers avatar omnone avatar philnash avatar someoneweird avatar the-eater avatar thelinmichael avatar vincentorback avatar zhuwxyz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spotify-web-api-node's Issues

reorderTracksInPlaylist documentation missing

not a huge deal, but i had to dive into the code to find this one:

line 1096

  /**
   * Reorder tracks in a playlist.
   * @param {string} userId The playlist's owner's user ID
   * @param {string} playlistId The playlist's ID
   * @param {int} rangeStart The position of the first track to be reordered.
   * @param {int} insertBefore The position where the tracks should be inserted.
   * @param {Object} options Optional parameters, i.e. range_length and snapshot_id.
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
   * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected,
   * it contains an error object. Not returned if a callback is given.
   */
  this.reorderTracksInPlaylist = function(userId, playlistId, rangeStart, insertBefore, options, callback) {
  }

it would be great to have the documentation include this function for future users.

GetTracks API

Hi!
The GetTracks API should have an option to make the call with slices of 50 tracks (max) and give the result back.

addTracksToPlaylist throws 414 with lots of tracks

Hey

I'm trying to add 100 tracks to a playlist but the url is too long and fails. 414 - Request-URI Too Long
The API documentation say that you can post the tracks in the body instead the query string. Maybe it would fix this?

[s]

Getting 404 errors when attempting to access a user's playlists

I'm using Node version 5.5.0, and spotify-web-api-node version 2.3.0. I'm using the following function to get the playlists from my own Spotify account.

var SpotifyWebApi = require('spotify-web-api-node');
var clientId = '<client id>';
var clientSecret = '<client secret>';

var spotifyApi = new SpotifyWebApi({
    clientId: clientId,
    clientSecret: clientSecret
});

function getUserPlaylists(userId) {
    spotifyApi.clientCredentialsGrant()
        .then(function(data) {
            spotifyApi.setAccessToken(data.body['access_token']);
            spotifyApi.getUserPlaylists(userId)
                .then(function(data) {
                    console.log(data);
                }, function(err) {
                    console.log('Something went wrong!', err);
                });
        }, function(err) {
            console.log('Something went wrong when retrieving an access token', err);
        });
}

However, whenever I call this function with my own Spotify user ID (I signed up with Facebook), I get the following error: Something went wrong! { [WebapiError: Not found.] name: 'WebapiError', message: 'Not found.', statusCode: 404 }. Other API functions work still, but all of a sudden this one ceased to work even though I haven't touched my server or the code for my server since it was working well. I checked the endpoints in the spotify-web-api-node source code and they seem to still be correct for getUserPlaylists.

Query params aren’t sent properly

  • node: 6.6.0
  • npm: 3.10.7
  • spotify-web-api-node: 2.3.5

Test code

spotifyApi.getPlaylist(user, playlist, {
  offset: 5,
  limit: 10,
}).then((data) => console.log(data.body.tracks.next));

Current behaviour:

The above code logs the URL:

https://api.spotify.com/v1/users/{user}/playlists/{playlist}/tracks?offset=10&limit=10

Expected behaviour:

It should log following URL, confirmed via the Spotify Web API Console.

https://api.spotify.com/v1/users/{user}/playlists/{playlist}/tracks?offset=15&limit=10

Suggestion

Interestingly, the offset in the next URL appears to work. The offset parameter, however, seems to be ignored. I tried to find the issue myself, but no luck thus far.

My guess is that the offset parameter is accidentally omitted when an URL is generated.

Remove track without snapshot_id

According the spotify API, snapshot_id is not mandatory. It seems to be in this interface, though. Is there a reason? If so, how do you retrieve a snapshot_id for a playlist?

authorizationCodeGrant() is not included in the browser bundle

Hello,
I'm trying to authenticate an user but the resulting instance doesn't have any of the server methods.

import SpotifyWebApi from 'spotify-web-api-node';

const credentials = {
  clientId: `clientId`,
  clientSecret: `clientSecret,`
  redirectUri: 'http://localhost:3000/callback'
};

const SpotifyApi = new SpotifyWebApi(credentials);
...

SpotifyApi.authorizationCodeGrant(...code);
undefined

Error 401

When the the server has been running for a while and you call spotifyApi.SearchTrack() it returns
{ [WebapiError: Unauthorized] name: 'WebapiError', message: 'Unauthorized', statusCode: 401 }
It starts working again if the server is restarted. Any idea why this is happening?

Is there a way to check expiration status of access token?

After my access token expires I get an error saying 'Unauthorized.' This is expected since my token has expired, but is there a way to check on the expiration status of the token to see if we need to refresh it before the request is made? I was thinking I could calculate the expiration datetime when first receiving the token and check before each request to see if it's past that time, but wondering if this was built in already. Thanks!

Trouble with Invalid redirect URI

I'm following the code in the example and using express ... when receive the callback from spotify, I call the following function

app.get('/auth/spotify/callback',
  function(req, res){
    // The request will be redirected to spotify for authentication, so this
    // function will not be called.

    /* Read query parameters */
    var authorizationCode  = req.query.code; // Read the authorization code from the query parameters
    var state = req.query.state; // (Optional) Read the state from the query parameter

    console.log('authorizationCode ' + authorizationCode);
    console.log('state ' + state);

    spotifyApi.authorizationCodeGrant(authorizationCode)
      .then(function(data) {

        // Set the access token and refresh token
        console.log('The token expires in ' + data['expires_in']);
        console.log('The access token is ' + data['access_token']);
        console.log('The refresh token is ' + data['refresh_token']);

        spotifyApi.setAccessToken(data.body['access_token']);
        spotifyApi.setRefreshToken(data.body['refresh_token']);

        res.redirect('/home');

        // Save the amount of seconds until the access token expired
        tokenExpirationEpoch = (new Date().getTime() / 1000) + data.body['expires_in'];
        console.log('Retrieved token. It expires in ' + Math.floor(tokenExpirationEpoch - new Date().getTime() / 1000) + ' seconds!');
      }, function(err) {
        console.log('Something went wrong when retrieving the access token!', err.message);
        //res.redirect('/home');
        console.log('Something went wrong when retrieving the access token!', err);
      });
  });

I've tripple checked that the URI is actually added to the whitelist and that I am setting it when I instantiate everything

var spotifyApi = new SpotifyWebApi({
  clientId : client_id,
  clientSecret : client_secret,
  redirectUri : 'http://www.example.com/callback'
});

I can't figure out for the life of me why it keeps throwing this error

 name: 'WebapiError',
  message: 'invalid_grant: Invalid redirect URI',
  statusCode: undefined }

Response headers on error callback

At the moment there is no possibility to fetch the Retry-After response header if there was an error 429 (rate limiting). This information would be needed to develop a resume/retry logic.

A way to access older snapshot_ids in retrospect?

I was wondering if the ability to access older states of a playlist (eg. Discover Weekly) is implemented.

I'm aware of this IFTTT applet, but if I understand this correctly, it works from the point you enable it forward.

So, can I access older snapshot_ids?

How to use OAuth token to create playlist?

I'm trying to create a playlist but I need to authenticate. I'm using the client credentials grant.

I'm able to get the access token, but authorizationCodeGrant is failing when I pass the token in. How should I change this so that authorizationCodeGrant works? Is this the correct way to be creating a playlist?

// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
  clientId : config.spotifyid,
  clientSecret : config.spotifysecret
});

// Retrieve an access token.
spotifyApi.clientCredentialsGrant()
  .then(function(data) {
    console.log('The access token expires in ' + data.body['expires_in']);
    console.log('The access token is ' + data.body['access_token']);

    // Save the access token so that it's used in future calls
    spotifyApi.setAccessToken(data.body['access_token']);
    const authorizationCode = data.body['access_token'];

	  spotifyApi.authorizationCodeGrant(authorizationCode)
	  .then(function(data) {
	    // spotifyApi.setAccessToken(data.body['access_token']);
		return spotifyApi.createPlaylist('kabirvirji', 'My Cool Playlist', { 'public' : false })
		  .then(function(data) {
		    console.log('Created playlist!');
		  }, function(err) {
		    console.log('Something went wrong!', err);
		  });
		}, function(err) {
			console.log('authorizationCodeGrant error', err);
		});

// This is the error being thrown
  }, function(err) {
        console.log('Something went wrong when retrieving an access token', err);
  });

refresh token

Hey,

I'm having issues using the refresh token to get a new access token. Is there anythign I need to do besides using the setRefreshToken method?

Thanks,

Tom

Collaborator?

Hello -- I am going to use this module heavily and so I think it'd be great if we could be collaborators on this project both on GitHub and NPM. Double whammy power. Would you be open to sharing access?

Application flow

Apologies if this sounds like a stupid question, but how would I use access/refresh tokens in my app to authenticate a user or send a user to the authorise URL?

https://github.com/benchmarkstudios/slackbox/blob/master/app.js

If I run auth() instead of findTrack('track') on initialisation (Line 42), I get an authorisation URL in the console, which in turns gives me a code. If I paste this in to Line 9 and re-run - then the app works as needed.

However, if I try and run this again, obviously code becomes invalid and I have to repeat the process again, which isn't ideal, so I'm just wondering where I might be going wrong?

Any help appreciated!

replaceTracksInPlaylist is missing a range_start parameter

When the replaceTracksInPlaylist method is invoked, Spotify returns an error that the request is missing a range_start parameter. Looking at the Spotify API documentation on replace a playlist's tracks, it would not appear that this field is required, except that it's actually using the same endpoint (https://api.spotify.com/v1/users/{user_id}/playlists/{playlist_id}/tracks) as reorder tracks, for which range_start is a required param.

The fix would likely be to add a range_start parameter (hard-coded to 0?) to the body of the post.

spotifyApi.replaceTracksInPlaylist(userId, playlistId, trackIds)

{ [WebapiError: Missing range_start parameter]
name: 'WebapiError',
message: 'Missing range_start parameter',
statusCode: 400 }

JSON Error

Currently the promise for errors returns a string as an error, e.g.

err = {
  "error": {
    "status": 401,
    "message": "The access token expired"
  }
}

Can we have this wrapped in a try/catch block to parse as JSON?

Maybe get some inspiration from the node-sincerely or other API wrappers I've built.

Also I think that err should just be the error message, and then you should have a response perhaps with the actual JSON response.

Installing the nodejs package

Node.js Command prompt output

npm ERR! Windows_NT 10.0.14393
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install" "spotify-web-api-node" "--save"
npm ERR! node v4.4.7
npm ERR! npm v2.15.8
npm ERR! file C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
npm ERR! code EJSONPARSE

npm ERR! Failed to parse json
npm ERR! Trailing comma in object at 6:1
npm ERR! }
npm ERR! ^
npm ERR! File: C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
npm ERR! Failed to parse package.json data.
npm ERR! package.json must be actual JSON, not just JavaScript.
npm ERR!
npm ERR! This is not a bug in npm.
npm ERR! Tell the package author to fix their package.json file. JSON.parse

npm ERR! Please include the following file with any support request:
npm ERR! C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\npm-debug.log

C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch>npm install spotify-web-api-node
npm ERR! Windows_NT 10.0.14393
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install" "spotify-web-api-node"
npm ERR! node v4.4.7
npm ERR! npm v2.15.8
npm ERR! file C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
npm ERR! code EJSONPARSE

npm ERR! Failed to parse json
npm ERR! Trailing comma in object at 6:1
npm ERR! }
npm ERR! ^
npm ERR! File: C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
npm ERR! Failed to parse package.json data.
npm ERR! package.json must be actual JSON, not just JavaScript.
npm ERR!
npm ERR! This is not a bug in npm.
npm ERR! Tell the package author to fix their package.json file. JSON.parse

npm ERR! Please include the following file with any support request:
npm ERR! C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\npm-debug.log

npn-debug.log

0 info it worked if it ends with ok
1 verbose cli [ 'C:\Program Files\nodejs\node.exe',
1 verbose cli 'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js',
1 verbose cli 'install',
1 verbose cli 'spotify-web-api-node' ]
2 info using [email protected]
3 info using [email protected]
4 verbose install initial load of C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
5 verbose stack Error: Failed to parse json
5 verbose stack Trailing comma in object at 6:1
5 verbose stack }
5 verbose stack ^
5 verbose stack at parseError (C:\Program Files\nodejs\node_modules\npm\node_modules\read-package-json\read-json.js:390:11)

5 verbose stack at parseJson (C:\Program Files\nodejs\node_modules\npm\node_modules\read-package-json\read-json.js:79:23)
5 verbose stack at C:\Program Files\nodejs\node_modules\npm\node_modules\read-package-json\read-json.js:48:5
5 verbose stack at C:\Program Files\nodejs\node_modules\npm\node_modules\graceful-fs\graceful-fs.js:78:16
5 verbose stack at FSReqWrap.readFileAfterClose as oncomplete
6 verbose cwd C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch
7 error Windows_NT 10.0.14393
8 error argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install" "spotify-web-api-node"
9 error node v4.4.7
10 error npm v2.15.8
11 error file C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
12 error code EJSONPARSE
13 error Failed to parse json
13 error Trailing comma in object at 6:1
13 error }
13 error ^
14 error File: C:\Users\Broccoli-GO\Desktop\scripts\bots\twitch\package.json
15 error Failed to parse package.json data.
15 error package.json must be actual JSON, not just JavaScript.
15 error
15 error This is not a bug in npm.
15 error Tell the package author to fix their package.json file. JSON.parse
16 verbose exit [ 1, true ]

authorizationCodeGrant is not a function

Hi there.

I'm trying to authorize my Spotify account using you're example code as shown below:

var credentials = {
  clientId : 'someClientId',
  clientSecret : 'someClientSecret',
  redirectUri : 'http://www.michaelthelin.se/test-callback'
};

var spotifyApi = new SpotifyWebApi(credentials);

// The code that's returned as a query parameter to the redirect URI
var code = 'MQCbtKe23z7YzzS44KzZzZgjQa621hgSzHN';

// Retrieve an access token and a refresh token
spotifyApi.authorizationCodeGrant(code)
  .then(function(data) {
    console.log('The token expires in ' + data.body['expires_in']);
    console.log('The access token is ' + data.body['access_token']);
    console.log('The refresh token is ' + data.body['refresh_token']);

    // Set the access token on the API object to use it in later calls
    spotifyApi.setAccessToken(data.body['access_token']);
    spotifyApi.setRefreshToken(data.body['refresh_token']);
  }, function(err) {
    console.log('Something went wrong!', err);
  });

But I can't seem to pass the authorizationCodeGrant part.

    this.spotifyApi = new SpotifyWebApi({
      clientId : '1234567',
      clientSecret : '8901234',
      redirectUri : 'http://localhost:6001/cv'
    });

    const scopes = ['user-read-private', 'user-read-email'];
    const state = '34fFs29kd09';

    const authorizeURL = this.spotifyApi.createAuthorizeURL(scopes, state);
    console.info(authorizeURL);

    this.spotifyApi.authorizationCodeGrant(code)
      .then(function(data) {
        console.log('The token expires in ' + data.body['expires_in']);
        console.log('The access token is ' + data.body['access_token']);
        console.log('The refresh token is ' + data.body['refresh_token']);

        // Set the access token on the API object to use it in later calls
        this.spotifyApi.setAccessToken(data.body['access_token']);
        this.spotifyApi.setRefreshToken(data.body['refresh_token']);
      }, function(err) {
        console.log('Something went wrong!', err);
      });

The URL given made my authorize and I've accepted. From there I'd get a new extremely long code:
12345678901§2345678901234567890&state=34fFs29kd09

Of course my code is different, but I don't know exactly if I'll have to use this code with or without the state parameter to the authorizationCodeGrant function.

this.spotifyApi.authorizationCodeGrant is not a function

As my title suggests I can't seem to use the function authorizationCodeGrant as it says it does not exists. Any idea whats up?

search() method doesn't work properly

Hi,

I'm trying to use the search() method and it basically gives me a mostly empty object.
This is what I get:

{ tracks:
   { href: 'https://api.spotify.com/v1/search?query=Du+bist+sch%C3%B6n&offset=1&limit=1&type=track',
     items: [ [Object] ],
     limit: 1,
     next: 'https://api.spotify.com/v1/search?query=Du+bist+sch%C3%B6n&offset=2&limit=1&type=track',
     offset: 1,
     previous: 'https://api.spotify.com/v1/search?query=Du+bist+sch%C3%B6n&offset=0&limit=1&type=track',
     total: 2041 } }

Here's the code I'm executing with Git Bash (not gonna share my clientId and clientSecret of course, but they are there and correct):

var SpotifyWebApi = require('spotify-web-api-node');
var spotifyApi = new SpotifyWebApi({
    clientId: <clientID>,
    clientSecret: <clientSecret>,   
        redirectUri: 'http://localhost:8888/callback',
});
spotifyApi.search('Du bist schön', ['track'], { limit : 1, offset: 1}, function(err, data) {
    if (err) {
        console.error(err);
    } else {
    console.log(data.body)
    }
});

If I try this data.body["tracks"] it gives me more information:

{ href: 'https://api.spotify.com/v1/search?query=Du+bist+sch%C3%B6n&offset=0&limit=1&type=track',
  items:
   [ { album: [Object],
       artists: [Object],
       available_markets: [Object],
       disc_number: 1,
       duration_ms: 228213,
       explicit: false,
       external_ids: [Object],
       external_urls: [Object],
       href: 'https://api.spotify.com/v1/tracks/5PJeAJAw8YFUesmwARqn9Y',
       id: '5PJeAJAw8YFUesmwARqn9Y',
       name: 'Du bist schön',
       popularity: 68,
       preview_url: 'https://p.scdn.co/mp3-preview/04b971fb3e032f162d0096e442073a25c085cfb6',
       track_number: 11,
       type: 'track',
       uri: 'spotify:track:5PJeAJAw8YFUesmwARqn9Y' } ],
  limit: 1,
  next: 'https://api.spotify.com/v1/search?query=Du+bist+sch%C3%B6n&offset=1&limit=1&type=track',
  offset: 0,
  previous: null,
  total: 2041 }


but that's still not everything, as you can see. I tried using an access token (I have another function that gives me the audio features of a song) but I get the same result. I also tried using promises but still the same.
What am I doing wrong here? Please keep in mind that I'm fairly new to JavaScript and Node.
Also I do not really need everything, mostly I'd like to get the artist, name of the track and the id. How do I get only these things?

Improper encoding for getPlaylist causes the request to fail.

In this request https://api.spotify.com/v1/users/spotify_españa/playlists/6WCc127FLZ5hztL9gpFT3j the playlist owner spotify_españa has an accented character, when passed through the library this causes a 400 response due to the character encoding of that string. I'm currently mitigating this by callingencodeURIComponent(<playlist owner>) before calling getPlaylist - but really this should be handled by spotify-web-api-node.

Issue of IOS devices and IE11

i was developing one app to follow me by others and facing some issues on ios and IE11.

ios issue : unable get authentication...when ever i am clicking the authentication button to follow me, nothing is happening.but this works fine on android chrome firefox. When i add "/?" at the end of redirect URI, it will works fine.pls help on this.

IE11 issue....i am unable to follow anyone when i am using IE11.i guess promises function are not working on IE11....pls help onthis too..

Thanks !

removeTracksFromPlaylist example in README.md is incorrect

This example does not work. It causes a Bad Request.

var tracks = { tracks : [{ uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh" }] };
var options = { snapshot_id : "0wD+DKCUxiSR/WY8lF3fiCTb7Z8X4ifTUtqn8rO82O4Mvi5wsX8BsLj7IbIpLVM9" };
spotifyApi.removeTracksFromPlaylist('thelinmichael', '5ieJqeLJjjI8iJWaxeBLuK', tracks, options)
  .then(function(data) {
    console.log('Tracks removed from playlist!');
  }, function(err) {
    console.log('Something went wrong!', err);
  });

The issue lies with the tracks variable, which is not in the correct format.

Should be:

var tracks = [{ uri : "spotify:track:4iV5W9uYEdYUVa79Axb7Rh" }];

I verified this after taking a look at the source code

removeTracksFromPlaylist: function(userId, playlistId, tracks, options, callback) {
    var request = WebApiRequest.builder().
      withPath('/v1/users/' + encodeURIComponent(userId) + '/playlists/' + playlistId + '/tracks').
      withHeaders({ 'Content-Type' : 'application/json' }).
      withBodyParameters({
        'tracks': tracks // the object is being created here
      })

I suppose you would have to change the docs and not the input as this would be a breaking change.

list of locale's

Is there a way to ge a list of all spotify locale's?

Thanks!

Tom

Prevent serialization of Buffer and Promise to reduce bundle size when browserifying

Superagent uses a browser property in its package.json to provide a different entry point to the library when bundling for browser use. This is great, since it prevents browserify from bundling the implementation to make requests using node.

It turns out that the browser property is not transitive. Thus, a project importing spotify-web-api-node and using webpack/browserify to bundle, will bring that node code together. The resulting size of the spotify-web-api-node bundle is 90kB minified not-gzipped. Bundling just superagent results in 15kB, and this library shouldn't add too much on top of it.

We should expose a browser entry point in the package.json file for this project that points to the browser implementation of superagent, or find out a way to make the property transitive.

Access to response headers

Accessing response headers is important to be able to handle caching. Therefore, make the headers optionally available in all responses.

More debugging information would be nice

I'm having some issues where it would be nice to see more details about the http requests and responses to the Spotify API. For instance, WebapiError looks like:

{
    "name": "WebapiError",
    "message": "Unauthorized",
    "statusCode": 401
  }

However, when I add an additional line of logging here:

/* Create an error object from an error returned from the Web API */
var _getErrorObject = function(defaultMessage, err) {
  console.log('got err', JSON.stringify(err, null, 2));

I get:

{
  "error": {
    "original": null,
    "response": {
      "req": {
        "method": "PUT",
        "url": "https://api.spotify.com/v1/me/albums",
        "data": "\"5XNpjmlGWc9XzX1XjH5lv7\"",
        "headers": {
          "user-agent": "node-superagent/2.3.0",
          "content-type": "application/json"
        }
      },
      "header": {
        "server": "nginx",
        "date": "Sun, 13 Nov 2016 15:43:39 GMT",
        "content-type": "application/json",
        "transfer-encoding": "chunked",
        "connection": "close",
        "www-authenticate": "Bearer realm=\"spotify\"",
        "access-control-allow-origin": "*",
        "access-control-allow-methods": "GET, POST, OPTIONS, PUT, DELETE",
        "access-control-allow-credentials": "true",
        "access-control-max-age": "604800",
        "access-control-allow-headers": "Accept, Authorization, Origin, Content-Type",
        "content-encoding": "gzip"
      },
      "status": 401,
      "text": "{\n  \"error\": {\n    \"status\": 401,\n    \"message\": \"No token provided\"\n  }\n}"
    },
    "status": 401
  }
}

This additional information would be useful! 😄

Don't encode the colons separating the query fields in searchTracks()

As we can see in the api docs, we should not encode the colons which separate the query fields (artist, track, album etc)
https://developer.spotify.com/web-api/search-item/

The searchTracks() example from the main page call this url (with 'artist:Love')
https://api.spotify.com/v1/search?query=artist%3ALove&offset=0&limit=20&type=track
It should be https://api.spotify.com/v1/search?query=artist:Love&offset=0&limit=20&type=track

Otherwise the returned results aren't correct.

authorizationCodeGrant seems timing out?

We have a auth flow where our android app send the auth code to the server, and server makes a authorizationCodeGrant api call to get the accessToken and refreshToken, currently the call is timing out. Is this a correct flow and is it suppose to work, note that the redirect URI on android is not a http url but a custom scheme.

invalid request for getRecomendations

Calling getRecomendations from the example in source code throws an error. In the example below, getAudioFeaturesForTracks will return a valid response while getRecommendations will return the following err:

{ [WebapiError: invalid request]
  name: 'WebapiError',
  message: 'invalid request',
  statusCode: 400 }
spotifyApi.clientCredentialsGrant()
  .then(function(data) {
    console.log('The access token expires in ' + data.body['expires_in']);
    console.log('The access token is ' + data.body['access_token']);

    // Save the access token so that it's used in future calls
    spotifyApi.setAccessToken(data.body['access_token']);
  }, function(err) {
        console.log('Something went wrong when retrieving an access token', err);
  })
  .then(function(){
    spotifyApi.getAudioFeaturesForTracks(['38P3Q4QcdjQALGF2Z92BmR', '2HO2bnoMrpnZUbUqiilLHi']).then(function(data){
      console.log(data.body.audio_features)
    }, function(err){
      console.log(err)
    })
    spotifyApi.getRecommendations({ min_energy: 0.4, seed_artists: ['6mfK6Q2tzLMEchAr0e9Uzu', '4DYFVNKZ1uixa6SQTvzQwJ'], min_popularity: 50 })
      .then(function(data) {
        console.log(data);
      }, function(err) {
        console.log(err);
      });
  });

this.getRecommendations returns an "invalid request" error

When running the getRecommendations function using the wrapper, an error is returned saying it is an invalid request. Turns out, it's because the seed_artists, seed_genres, and seed_tracks are being sent as arrays in the query string rather than comma separated strings. This is simply solved by adding .join(',') on the end of the arrays that are sent, but this isn't specified in the docs. Please either update the dogs or have the arrays turned into strings automatically. That would have saved me a lot of headache.

how to iterate with next options?

I'm looking at iterating through a list of tracks in a playlist. The limit is set at 20 right now. How do I use this framework to iterate through all records? Could you point me towards an example?

Thanks!

NPM has no README.md

I know with one of my friends packages the README.md file was not distributed to NPM. Some bug in NPM. Just noticed this package does not have a README on NPM either.

Bad request

Hi there,

I'm trying to make a request, but I really don't get what I'm doing wrong, error messages like shown below keep showing up:

Something went wrong on auth! { [WebapiError: Bad Request] name: 'WebapiError', message: 'Bad Request', statusCode: 400 }

and

Something went wrong on playlists! { [WebapiError: Unauthorized] name: 'WebapiError', message: 'Unauthorized', statusCode: 401 }

This afternoon I got it working once, but now the access token is expired or something I guess? But when I'll run the refresh function you posted in the authorization section I'll get:

Could not refresh access token { [WebapiError: Bad Request] name: 'WebapiError', message: 'Bad Request', statusCode: 400 }

How can I debug this? What can I do?
If it helps, here is my SpotifyClient class:

import SpotifyWebApi from 'spotify-web-api-node';

class SpotifyClient {
  constructor(username) {
    this.username = username;

    this.spotifyApi = new SpotifyWebApi({
      clientId : 'CLIENT_ID',
      clientSecret : 'CLIENT_SECRET',
      redirectUri : 'http://localhost:6001/cv',
      accessToken : 'HERE_WAS_THE_CODE'
    });

    // this.setAuthorization();
    this.refreshAuthorization();
  }

  setAuthorization() {
    const scopes = ['user-read-private', 'user-read-email'];
    const state = 't3st';

    const authorizeURL = this.spotifyApi.createAuthorizeURL(scopes, state);
    console.log(authorizeURL);

    const code = 'HERE_WAS_THE_CODE_FROM_AUTH_URL';

    this.spotifyApi.authorizationCodeGrant(code)
      .then(function(data) {
        console.log('The token expires in ' + data.body['expires_in']);
        console.log('The access token is ' + data.body['access_token']);
        console.log('The refresh token is ' + data.body['refresh_token']);

        // Set the access token on the API object to use it in later calls
        this.spotifyApi.setAccessToken(data.body['access_token']);
        this.spotifyApi.setRefreshToken(data.body['refresh_token']);
      }, function(err) {
        console.log('Something went wrong on auth!', err);
      });
  }

  refreshAuthorization() {
    this.spotifyApi.refreshAccessToken()
      .then(function(data) {
        console.log('The access token has been refreshed!');

        // Save the access token so that it's used in future calls
        this.spotifyApi.setAccessToken(data.body['access_token']);
      }, function(err) {
        console.log('Could not refresh access token', err);
      });
  }

  getPlaylistById(callback) {
    console.info('spotify client get');

    this.spotifyApi.getPlaylist(this.username, '2tj5TA5I1QySyHI3YdpXYj')
      .then(function(data) {
        // console.log('Some information about this playlist', data.body);
        console.info('spotify client did return');
        // return data.body;

        callback(null, data.body);
      }, function(err) {
        console.log('Something went wrong on playlists!', err);
      });
  }
}

export default SpotifyClient;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.