jlund / spotify-export

A simple Ruby utility that uses Spotify's Web API to export a playlist as plain text
MIT License
293 stars 42 forks source link

undefined method `each' for nil:NilClass #17

Open OwenRay opened 7 years ago

OwenRay commented 7 years ago

The application throws an exception when trying the example command:

$ ./bin/spotify-export.rb spec/support/multiple-tracks.txt

/Users/owenray/spotify-export/lib/spotify-track.rb:49:in `format_artists': undefined method `each' for nil:NilClass (NoMethodError)
    from /Users/owenray/spotify-export/lib/spotify-track.rb:82:in `get_track_attributes'
    from /Users/owenray/spotify-export/lib/spotify-track.rb:32:in `attributes'
    from /Users/owenray/spotify-export/lib/spotify-track.rb:22:in `name'
    from bin/spotify-export.rb:23:in `block in <main>'
    from bin/spotify-export.rb:20:in `each'
    from bin/spotify-export.rb:20:in `each_with_index'
    from bin/spotify-export.rb:20:in `<main>'

Running on macOS Sierra 10.12.5 ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]

OwenRay commented 7 years ago

just noticed this gets resolved by https://github.com/jlund/spotify-export/pull/14

xaviarias commented 7 years ago

I have the same issue here, but In my case #14 does not solve the problem, it causes infinite recursion. The problem seems that artists parameter is null, not a typo.

fredericoabraham commented 6 years ago

I'm getting it here too. git reset'ed (9/17/2017). Anyone found a solution for this? Thanks

BachirC commented 6 years ago

The problem is that the API call to Spotify in lib/spotify-track.rb is returning a 401 because no token is passed with the request. As stated by the API used in this gem, https://developer.spotify.com/web-api/get-track/ you will need to implement an Authorization workflow (https://developer.spotify.com/web-api/authorization-guide/) to generate a user token that will be passed in the requests to Spotify.

BachirC commented 6 years ago

How I made it work :

For this part, you will need to Base64 encode the string client_id:client_secret of your Spotify app. I used this https://www.base64encode.org/. Also, beware to pass the grant_type params in the body and not as an URL-encoded param otherwise you will get a 400.

lib/spotify-track.rb

  def get_track_attributes
    if local
      local_array = uri.split(':')

      # The array should be length 6
      # ["spotify", "local", "artist", "album", "song title", "duration"]
      name   = URI.decode(local_array[4].gsub('+', ' '))
      album  = URI.decode(local_array[3].gsub('+', ' '))
      artist = URI.decode(local_array[2].gsub('+', ' '))
    else
      track_id = uri[/track(:|\/)(.+)/, 2]
      target  = URI.parse("https://api.spotify.com/v1/tracks/#{ track_id }")
      http    = Net::HTTP.new(target.host, target.port)
      http.use_ssl = true
      request = Net::HTTP::Get.new(target.request_uri)
      access_token = "Zwejkrhqwlkrq..."
      request['Authorization'] = "Bearer #{access_token}"

If I have some time, I'll do a PR to allow a user to pass the access token directly in the args when launching the script (the access token generation will be done manually as I explained above). It is not optimal as the token will stay in your bash history but for now it'll do and I'm sure we'll come up with a better solution. Hope this helps.

⚠️ Don't commit or share your Spotify token.

fredericoabraham commented 6 years ago

Hi. Still trying to make this work. Does the token look something like this after base 64 encode? (I messed with it so it's wrong):

  access_token = "YTU5YTc3AmVmADk4NDI2M2E2MGU2ZTU4NGFiYWYyM2Y="

Thanks.

BachirC commented 6 years ago

Looks like it, yes. Did you try it out ?

BachirC commented 6 years ago

Ok wait didn't read well. It's not the token that should be base64 encoded, it is the string client_id:client_secret.

Checkout the second link I posted in my workflow, it is well explained.

glfaulkner commented 6 years ago

Still throwing me the same exception, even with adding the access token (which I obtained with curl passing the base64 string) to spotify-track.rb. When encoding the client id and secret to base64, does the string need to follow the exact 'client_id:client_secret" format, with the colon in the middle?

Thanks.

regisbsb commented 6 years ago

It works, cheers!

BachirC commented 5 years ago

@glfaulkner Yes it does.

fredericoabraham commented 4 years ago

Hello all. I've been trying to use spotify-export again, but haven't been able to log in to the developer site. Wanted to know if you guys could: https://developer.spotify.com/ https://developer.spotify.com/web-api/get-track/ I try to log in, when clicking on dashboard shows the same as before, as if I wasn't logged in.

Thanks, -- Fred

On Sat, Oct 13, 2018 at 11:10 AM Bachir notifications@github.com wrote:

@glfaulkner https://github.com/glfaulkner Yes it does.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/jlund/spotify-export/issues/17#issuecomment-429545186, or mute the thread https://github.com/notifications/unsubscribe-auth/ABLxdlRlJvF9utS2w5F1btQKn_Be9OP3ks5ukfQ5gaJpZM4ONXwC .

-- -- Fred

OwenRay commented 4 years ago

@snakenerd works for me, I'm logging in with username & password if that helps.

yijiangh commented 1 year ago

Complementing the awesome instructions above, for those who are as new to javascript as me, you need to run the following script (adapted from the example from Spotify that's not directly runnable 😂):

var request = require('request'); // "Request" library

var client_id = 'YOUR CLIENT ID';
var client_secret = 'YOUR CLIENT SCRET';

var authOptions = {
  url: 'https://accounts.spotify.com/api/token',
  headers: {
    'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
  },
  form: {
    grant_type: 'client_credentials'
  },
  json: true
};

request.post(authOptions, function(error, response, body) {
  if (!error && response.statusCode === 200) {
    var token = body.access_token;
    console.log(token);
  }
});

So the steps are:

  1. Save the snippet above into a file called fetch_token.js. Fill in the client_id and client_secret. You don't have to encode them to base64 since Buffer does it for you.
  2. You can run it with, for example, nodejs: node fetch_token.js
  3. It will return your with a token, you don't have to encode or decode it any further, just copy it.
  4. change te lib/spotify-track.rb as suggested above, fill in your copied token in the line access_token = "...".
  5. Run ./bin/spotify-export.rb your_playlist.text