user3173575
user3173575

Reputation: 23

Downloading a track from Soundcloud using Ruby SDK

I am trying to download a track from Soundcloud using the ruby sdk (soundcloud 0.2.0 gem) with an app. I have registered the app on soundcloud and the client_secret is correct. I know this because I can see my profile info and tracks using the app. Now when I try to download a track using the following code

@track = current_user.soundcloud_client.get(params[:track_uri])
data = current_user.soundcloud_client.get(@track.download_url)
File.open("something.mp3","wb"){|f|f.write(data)}

and when I open the file it has nothing in it. I've tried many approaches including the following one,

data = current_user.soundcloud_client.get(@track.download_url)
file = File.read(data)

And this one gives me an error

can't convert nil into String 

on line 13 which is in

app/controllers/store_controller.rb:13:in `read' 

that is the File.read function.

I have double checked that the track I am trying to download is public and downloadable. I tried to test the download_url that is being used explicitly by copying it from console and sending a request using Postman and it worked. I am not sure why it is not working with the app when other things are working so well.

What I want to do is to successfully be able to either download or at least get the data which I could store somewhere.

Version details : -
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
Rails 3.2.18
soundcloud 0.2.0

Upvotes: 2

Views: 583

Answers (1)

Oto Brglez
Oto Brglez

Reputation: 4193

There are few assumptions that you have to understand before doing this thing.

  • Not every track on SoundClound can be downloaded! Only tracks that are flagged as downloadable can be downloaded - your code has to consider that option!
  • Your track URL has to be "resolved" before you get to download_url and after you get download_url you have to use your client_id to get the final download URL.
  • Tracks can be big, and downlowding them requires time! You should never do tasks like this straight from your Rails app in your controller or model. If the tasks runs longer you always use some background worker or some other kind of background processing "thing" - Sidekiq for example.

Command-line client example

This is example of working client, that you can use to download tracks from SoundClound. Its using official Official SoundCloud API Wrapper for Ruby, assumes that you are using Ruby 1.9.x and its not dependent on Rails in any way.

# We use Bundler to manage our dependencies
require 'bundler/setup'

# We store SC_CLIENT_ID and SC_CLIENT_SECRET in .env
# and dotenv gem loads that for us
require 'dotenv'; Dotenv.load

require 'soundcloud'
require 'open-uri'

# Ruby 1.9.x has a problem with following redirects so we use this
# "monkey-patch" gem to fix that. Not needed in Ruby >= 2.x
require 'open_uri_redirections'

# First there is the authentication part.
client = SoundCloud.new(
  client_id: ENV.fetch("SC_CLIENT_ID"),
  client_secret: ENV.fetch("SC_CLIENT_SECRET")
)

# Track URL, publicly visible...
track_url = "http://soundcloud.com/forss/flickermood"

# We call SoundCloud API to resolve track url
track = client.get('/resolve', url: track_url)

# If track is not downloadable, abort the process
unless track["downloadable"]
  puts "You can't download this track!"
  exit 1
end

# We take track id, and we use that to name our local file
track_id = track.id
track_filename = "%s.aif" % track_id.to_s
download_url = "%s?client_id=%s" % [track.download_url, ENV.fetch("SC_CLIENT_ID")]

File.open(track_filename, "wb") do |saved_file|
  open(download_url, allow_redirections: :all) do |read_file|
    saved_file.write(read_file.read)
  end
end

puts "Your track was saved to: #{track_filename}"

Also note that files are in AIFF (Audio Interchange File Format). To convert them to mp3 you do something like this with ffmpeg.

ffmpeg -i 293.aif final-293.mp3

Upvotes: 6

Related Questions