Skip to content

Instantly share code, notes, and snippets.

@duncanbeevers
Forked from pheuter/sc-dl.js
Created March 22, 2012 12:16
Show Gist options
  • Star 57 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save duncanbeevers/2157987 to your computer and use it in GitHub Desktop.
Save duncanbeevers/2157987 to your computer and use it in GitHub Desktop.
Bookmarklet that generates download link for a Soundcloud upload
(function(window){var i,$sound,$buttonGroup;var $sounds=$(".sound");var clientId=require("config").get("client_id");var oauthToken=require("lib/connect").getAuthToken();var conversionHelper=require("lib/helpers/conversion-helper");var $downloadButton,size;var params,downloadUrl,onSuccess;for(i=$sounds.length-1;i>=0;i--){$sound=$($sounds[i]);var soundcloudUrl="https://soundcloud.com"+($sound.find(".soundTitle__title").attr("href")||window.location.pathname);params={url:soundcloudUrl,client_id:clientId};onSuccess=function($sound){return function(data){var params={client_id:clientId};downloadUrl=require("lib/url").stringify({query:params},data.stream_url+".mp3");$buttonGroup=$($sound.find(".sound__soundActions .sc-button-group")[0]);size=$buttonGroup.find(".sc-button:first")[0].className.match(/sc-button-((?:small)|(?:medium))/)[1];$downloadButton=$('<a class="sc-button sc-button-download sc-button-icon sc-button-responsive">Download</a>').attr({title:"Download this sound ("+conversionHelper.bytesToMB(data.original_content_size)+")",href:downloadUrl,download:$sound.find(".soundTitle__title").first().text()+".mp3"}).addClass("sc-button-"+size);if(0==$sound.find(".sc-button-download").length){$buttonGroup.append($downloadButton)}}}($sound);$.getJSON("http://api.soundcloud.com/resolve.json",params).success(onSuccess)}})(window);
(function(window) {
var i, $sound, $buttonGroup;
var $sounds = $(".sound");
var clientId = require("config").get("client_id");
var oauthToken = require("lib/connect").getAuthToken();
var conversionHelper = require("lib/helpers/conversion-helper");
var $downloadButton, size;
var params, downloadUrl, onSuccess;
for (i = $sounds.length - 1; i >= 0; i--) {
$sound = $($sounds[i]);
var soundcloudUrl = "https://soundcloud.com" + ($sound.find(".soundTitle__title").attr("href") || window.location.pathname);
params = {
url: soundcloudUrl,
client_id: clientId
};
onSuccess = (function($sound) {
return function(data) {
var params = {
client_id: clientId
};
downloadUrl = require("lib/url").stringify({ query: params }, data.stream_url + ".mp3");
$buttonGroup = $($sound.find(".sound__soundActions .sc-button-group")[0]);
size = ($buttonGroup.find(".sc-button:first")[0].className).match(/sc-button-((?:small)|(?:medium))/)[1];
$downloadButton = $('<a class="sc-button sc-button-download sc-button-icon sc-button-responsive">Download</a>').attr({
title: "Download this sound (" + conversionHelper.bytesToMB(data.original_content_size) + ")",
href: downloadUrl,
download:$sound.find(".soundTitle__title").first().text()+'.mp3'
}).addClass("sc-button-" + size);
if (0 == $sound.find(".sc-button-download").length) {
$buttonGroup.append($downloadButton);
}
};
})($sound);
$.getJSON("http://api.soundcloud.com/resolve.json", params).success(onSuccess);
}
})(window);
@duncanbeevers
Copy link
Author

If you have uglifyjs installed you can simply issue the following command.

curl -s https://raw.github.com/gist/2157987/1fc
9f57df09938cd5091ce28fa87aee659c93e5a/sc-dl.js | uglifyjs -q | pbcopy

@duncanbeevers
Copy link
Author

(function(a){function f(a){var b=a.find(".actionbar");return b.length?b:a.prepend('<div class="actionbar"><div class="actions"><div class="primary"></div></div></div>')}function e(a,b){var c=b.find(".actions"),d=c.find(".download");d.length||c.prepend('<a href="'+a.streamUrl+'" class="download pl-button" download="'+a.title+'" title="'+a.title+'">Download track</a>')}function d(a,b){var d=null;b.hasClass("nano")?d=f(b.closest(".track-title").find(".track")).css({marginLeft:"18px"}):b.hasClass("small")&&(d=f(b.find(".container"))),d&&c(a,d)}function c(a,b){var c=b.find(".download, .mock-download");if(!c.length){var d=$('<a class="pl-button mock-download"><span>Download</span></a>').css({backgroundImage:"url(http://soundcloud.com/images/icons_mini.png?unicorn26)",backgroundRepeat:"no-repeat",backgroundPosition:"-77px -236px",paddingLeft:"18px"}).attr("download",a.title+".mp3");b.find(".primary").append(d),d.attr("href",a.streamUrl)}}function b(a){var b=$.helpers,f=b.getPlayerTrack(b.getPlayerNode(a)),g=a.find(".actionbar");!f||(a.hasClass("player")?g.length?c(f,g):d(f,a):e(f,a))}var g,h,i=a.querySelectorAll("[data-sc-track]");for(g=0,h=i.length;g<h;g++)b($(i[g]))})(document)

@duncanbeevers
Copy link
Author

Added a minified version to the repo

@felixfischer
Copy link

A ready-to-use bookmarklet based on this gist can be found here: http://marklets.com/SoundCloud+Download+Enabler.aspx

@duncanbeevers
Copy link
Author

@felixfischer Thanks

@mcnemesis
Copy link

This is one awesome!

@mcnemesis
Copy link

But am wondering why in Firefox it fails!
Take for example this sound: http://soundcloud.com/babalani/afro-melody
Via Firefox (7.0.1 on OpenSuse 12.1), this is what is saved in the body of the mp3 (instead of the actual file):

<TITLE>Error</TITLE> An error occurred while processing your request.

Reference #50.2fb40395.1352806837.527a416

But in Chrome it works fine.

@xristouz
Copy link

Is there any plan to support "The Next Soundcloud"?

@colineberly
Copy link

Is there any way to bypass the disabled download button and still get this to work? So far, if theres a disabled download button already there, then this will not work.

@colineberly
Copy link

Ok... to the above, a sort of hack solution, using adblock plus add the following rule without quotes "soundcloud.com##.disabled"
and then it will work again.

@duncanbeevers
Copy link
Author

Updated to work with Soundcloud Next.

@Technowise
Copy link

I wrote a similar script that works for all browsers. It has a Greasemonkey/ User script here:
http://userscripts.org/scripts/show/154933
This also has Firefox and Chrome extensions (links in the above page).

@markpiro
Copy link

I found a couple bugs with this gist:

The download button will often get appended multiple times per sound class element. Moving the download button check to inside the onSuccess function fixes the issue:

if (0 == $sound.find(".sc-button-download").length) {
    $buttonGroup.append($downloadButton);
}

Second, if there is a "buy button" in a sound then there will be two buttonGroups captured resulting in duplicate download buttons. To fix we only want to select one buttonGroup:

$buttonGroup = $($sound.find(".sound__soundActions .sc-button-group")[0]);

Complete gist with fixes:

(function(window) {
    var i, $sound, $buttonGroup;

    var $sounds = $(".sound");
    var clientId = require("config").get("client_id");
    var oauthToken = require("lib/connect").getAuthToken();
    var conversionHelper = require("lib/helpers/conversion-helper");
    var $downloadButton, size;
    var params, downloadUrl, onSuccess;

    for (i = $sounds.length - 1; i >= 0; i--) {
        $sound = $($sounds[i]);

        var soundcloudUrl = "https://soundcloud.com" + ($sound.find(".soundTitle__title").attr("href") || window.location.pathname);

        params = {
            url: soundcloudUrl,
            client_id: clientId
        };

        onSuccess = (function($sound) {
            return function(data) {
                var params = {
                  client_id: clientId
                };
                downloadUrl = require("lib/url").stringify({ query: params }, data.stream_url + ".mp3");

                $buttonGroup = $($sound.find(".sound__soundActions .sc-button-group")[0]);
                size = ($buttonGroup.find(".sc-button:first")[0].className).match(/sc-button-((?:small)|(?:medium))/)[1];

                $downloadButton = $('<a class="sc-button sc-button-download sc-button-icon sc-button-responsive">Download</a>').attr({
                  title: "Download this sound (" + conversionHelper.bytesToMB(data.original_content_size) + ")",
                  href: downloadUrl
                }).addClass("sc-button-" + size);

                if (0 == $sound.find(".sc-button-download").length) {
                    $buttonGroup.append($downloadButton);
                }
            };
        })($sound);

        $.getJSON("http://api.soundcloud.com/resolve.json", params).success(onSuccess);
    }
})(window);

Other than those small nits, still works great! :)

@haroldSanchezb
Copy link

hi @markpiro i added HTML5 download Attribute,

download:$sound.find(".soundTitle__title").first().text()+'.mp3'

inside of $downloadButton

Greetings!

@marcandrebenoit
Copy link

@haroldSanchezb can you tell me where your code goes exactly ?

post your updated version if possible or just the updated $downloadButton version that you have :)

Thanks!

@haroldSanchezb
Copy link

hello @marcandrebenoit
apology for the delay, with the option that i said, would look like:

(function(window) {
    var i, $sound, $buttonGroup;

    var $sounds = $(".sound");
    var clientId = require("config").get("client_id");
    var oauthToken = require("lib/connect").getAuthToken();
    var conversionHelper = require("lib/helpers/conversion-helper");
    var $downloadButton, size;
    var params, downloadUrl, onSuccess;

    for (i = $sounds.length - 1; i >= 0; i--) {
        $sound = $($sounds[i]);

        var soundcloudUrl = "https://soundcloud.com" + ($sound.find(".soundTitle__title").attr("href") || window.location.pathname);

        params = {
            url: soundcloudUrl,
            client_id: clientId
        };

        onSuccess = (function($sound) {
            return function(data) {
                var params = {
                  client_id: clientId
                };
                downloadUrl = require("lib/url").stringify({ query: params }, data.stream_url + ".mp3");

                $buttonGroup = $($sound.find(".sound__soundActions .sc-button-group")[0]);
                size = ($buttonGroup.find(".sc-button:first")[0].className).match(/sc-button-((?:small)|(?:medium))/)[1];

                $downloadButton = $('<a class="sc-button sc-button-download sc-button-icon sc-button-responsive">Download</a>').attr({
                  title: "Download this sound (" + conversionHelper.bytesToMB(data.original_content_size) + ")",
                  href: downloadUrl,
                  download:$sound.find(".soundTitle__title").first().text()+'.mp3'
                }).addClass("sc-button-" + size);

                if (0 == $sound.find(".sc-button-download").length) {
                    $buttonGroup.append($downloadButton);
                }
            };
        })($sound);

        $.getJSON("http://api.soundcloud.com/resolve.json", params).success(onSuccess);
    }
})(window);

@duncanbeevers
Copy link
Author

@haroldSanchezb @marcandrebenoit Updated to the latest version posted by @haroldSanchezb. These changes are great.

@shrwnsan
Copy link

shrwnsan commented Apr 8, 2014

This still working for people? I tried recently and I get a "Failed - No file" via Chrome. Thanks in advance.

@haroldSanchezb @duncanbeevers

@haroldSanchezb
Copy link

hi @stechico still working, but remember, only works in single songs no in continuous songs, or playlists on stream.

@GustavoHahn
Copy link

Hello, Anyone know how I can use your code and put it in a contextmenu of chrome?

@shrwnsan
Copy link

Thanks @haroldSanchezb, I'll keep that in mind an retest. Cheers!

@haroldSanchezb
Copy link

@GustavoHahn is possible, simply set up your context menu that captures the link by pressing right click, and send that url to a script that makes the function of generating the link to download.

Greetings!

Copy link

ghost commented Jul 3, 2014

It seems that this works, although the filenames are just a string of letters and numbers with 128 at the end showing their bit rate. Any reason why I am running into this issue?

@thibmaek
Copy link

Doesn't work in Safari with newest SoundCloud

@Korayem
Copy link

Korayem commented Oct 11, 2014

This doesn't work on chrome. I guess soundcloud are changing their protection mechanisms.

@kjvarga
Copy link

kjvarga commented Oct 19, 2014

'require' is a missing reference. Perhaps SC is not using requireJS anymore?

@aleemb
Copy link

aleemb commented Nov 9, 2014

Yup, broken now. Is there a quick fix?

@haroldSanchezb
Copy link

Ok, i will check tonight

@kjvarga
Copy link

kjvarga commented Dec 1, 2014

Anything to report?

@hoang-himself
Copy link

Time to give this an update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment