Default
Default

Reputation: 299

Soundcloud API /stream endpoint giving 401 error

I'm trying to write a react native app which will stream some tracks from Soundcloud. As a test, I've been playing with the API using python, and I'm able to make requests to resolve the url, pull the playlists/tracks, and everything else I need.

With that said, when making a request to the stream_url of any given track, I get a 401 error.

The current url in question is: https://api.soundcloud.com/tracks/699691660/stream?client_id=PGBAyVqBYXvDBjeaz3kSsHAMnr1fndq1

I've tried it without the ?client_id..., I have tried replacing the ? with &, I've tried getting another client_id, I've tried it with allow_redirects as both true and false, but nothing seems to work. Any help would be greatly appreciated.

The streamable property of every track is True, so it shouldn't be a permissions issue.

Edit:

After doing a bit of research, I've found a semi-successful workaround. The /stream endpoint of the API is still not working, but if you change your destination endpoint to http://feeds.soundcloud.com/users/soundcloud:users:/sounds.rss, it'll give you an RSS feed that's (mostly) the same as what you'd get by using the tracks or playlists API endpoint.

The link contained therein can be streamed.

Upvotes: 14

Views: 3430

Answers (3)

Otto Sichert
Otto Sichert

Reputation: 81

As mentioned by @user208685 the solution can be a bit simpler by using the SoundCloud API v2:

  1. Obtain the track ID (e.g. using the public API at https://developers.soundcloud.com/docs)
  2. Get JSON from https://api-v2.soundcloud.com/tracks/TRACK_ID?client_id=CLIENT_ID
  3. From JSON parse MP3 progressive stream URL
  4. From stream URL get MP3 file URL
  5. Play media from MP3 file URL

Note: This link is only valid for a limited amount of time and can be regenerated by repeating steps 3. to 5.

Example in node (with node-fetch):

const clientId = 'YOUR_CLIENT_ID';

(async () => {
  let response = await fetch(`https://api.soundcloud.com/resolve?url=https://soundcloud.com/d-o-lestrade/gabriel-ananda-maceo-plex-solitary-daze-original-mix&client_id=${clientId}`);
  const track = await response.json();
  const trackId = track.id;

  response = await fetch(`https://api-v2.soundcloud.com/tracks/${trackId}?client_id=${clientId}`);
  const trackV2 = await response.json();
  const streamUrl = trackV2.media.transcodings.filter(
    transcoding => transcoding.format.protocol === 'progressive'
  )[0].url;

  response = await fetch(`${streamUrl}?client_id=${clientId}`);
  const stream = await response.json();
  const mp3Url = stream.url;

  console.log(mp3Url);
})();

For a similar solution in Python, check this GitHub issue: https://github.com/soundcloud/soundcloud-python/issues/87

Upvotes: 7

Serg
Serg

Reputation: 845

Since I have the same problem, the answer from @Default motivated me to look for a solution. But I did not understand the workaround with the permalink_url in the steps 2 and 3. The easier solution could be:

  1. Fetch for example user track likes using api-v2 endpoint like this:
https://api-v2.soundcloud.com/users/<user_id>/track_likes?client_id=<client_id>
  1. In the response we can finde the needed URL like mentioned from @Default in his answer:
collection: [
   {
      track: {
         media: {
            transcodings:[
                   ...
                  {
                     url: "https://api-v2.soundcloud.com/media/soundcloud:tracks:713339251/0ab1d60e-e417-4918-b10f-81d572b862dd/stream/progressive"
                  ...
                  }
               ]
            }

         }
...
]
  1. Make request to this URL with client_id as a query param and you get another URL with that you can stream/download the track

Note that the api-v2 is still not public and the request from your client probably will be blocked by CORS.

Upvotes: 5

Default
Default

Reputation: 299

Okay, I think I have found a generalized solution that will work for most people. I wish it were easier, but it's the simplest thing I've found yet.

  1. Use API to pull tracks from user. You can use linked_partitioning and the next_href property to gather everything because there's a maximum limit of 200 tracks per call.

  2. Using the data pulled down in the JSON, you can use the permalink_url key to get the same thing you would type into the browser.

  3. Make a request to the permalink_url and access the HTML. You'll need to do some parsing, but the url you'll want will be something to the effect of:

    "https://api-v2.soundcloud.com/media/soundcloud:tracks:488625309/c0d9b93d-4a34-4ccf-8e16-7a87cfaa9f79/stream/progressive"

    You could probably use a regex to parse this out simply.

  4. Make a request to this url adding ?client_id=... and it'll give you YET ANOTHER url in its return json.

  5. Using the url returned from the previous step, you can link directly to that in the browser, and it'll take you to your track content. I checked on VLC by inputting the link and it streams correctly.

Hopefully this helps some of you out with your developing.

Upvotes: 9

Related Questions