Instantly share code, notes, and snippets.

Embed
What would you like to do?
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);
@turian

This comment has been minimized.

Show comment
Hide comment
@turian

turian Mar 26, 2012

Can you convert this to a one-line cut and paste? What's the easiest way to do that?

turian commented Mar 26, 2012

Can you convert this to a one-line cut and paste? What's the easiest way to do that?

@duncanbeevers

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers

duncanbeevers Mar 26, 2012

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
Owner

duncanbeevers commented Mar 26, 2012

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

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers

duncanbeevers Mar 26, 2012

(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)
Owner

duncanbeevers commented Mar 26, 2012

(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

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers

duncanbeevers Apr 1, 2012

Added a minified version to the repo

Owner

duncanbeevers commented Apr 1, 2012

Added a minified version to the repo

@felixfischer

This comment has been minimized.

Show comment
Hide comment
@felixfischer

felixfischer May 6, 2012

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

felixfischer commented May 6, 2012

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

@duncanbeevers

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers
Owner

duncanbeevers commented May 8, 2012

@felixfischer Thanks

@mcnemesis

This comment has been minimized.

Show comment
Hide comment
@mcnemesis

mcnemesis Nov 13, 2012

This is one awesome!

mcnemesis commented Nov 13, 2012

This is one awesome!

@mcnemesis

This comment has been minimized.

Show comment
Hide comment
@mcnemesis

mcnemesis Nov 13, 2012

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.

mcnemesis commented Nov 13, 2012

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

This comment has been minimized.

Show comment
Hide comment
@xristouz

xristouz Nov 30, 2012

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

xristouz commented Nov 30, 2012

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

@incace

This comment has been minimized.

Show comment
Hide comment
@incace

incace Dec 1, 2012

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.

incace commented Dec 1, 2012

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.

@incace

This comment has been minimized.

Show comment
Hide comment
@incace

incace Dec 1, 2012

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.

incace commented Dec 1, 2012

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

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers

duncanbeevers Dec 27, 2012

Updated to work with Soundcloud Next.

Owner

duncanbeevers commented Dec 27, 2012

Updated to work with Soundcloud Next.

@Technowise

This comment has been minimized.

Show comment
Hide comment
@Technowise

Technowise Jan 8, 2013

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).

Technowise commented Jan 8, 2013

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

This comment has been minimized.

Show comment
Hide comment
@markpiro

markpiro Nov 20, 2013

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! :)

markpiro commented Nov 20, 2013

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

This comment has been minimized.

Show comment
Hide comment
@haroldSanchezb

haroldSanchezb Dec 8, 2013

hi @markpiro i added HTML5 download Attribute,

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

inside of $downloadButton

Greetings!

haroldSanchezb commented Dec 8, 2013

hi @markpiro i added HTML5 download Attribute,

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

inside of $downloadButton

Greetings!

@marcandrebenoit

This comment has been minimized.

Show comment
Hide comment
@marcandrebenoit

marcandrebenoit Jan 30, 2014

@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!

marcandrebenoit commented Jan 30, 2014

@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

This comment has been minimized.

Show comment
Hide comment
@haroldSanchezb

haroldSanchezb Feb 17, 2014

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);

haroldSanchezb commented Feb 17, 2014

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

This comment has been minimized.

Show comment
Hide comment
@duncanbeevers

duncanbeevers Mar 14, 2014

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

Owner

duncanbeevers commented Mar 14, 2014

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

@stechico

This comment has been minimized.

Show comment
Hide comment
@stechico

stechico 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

stechico 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

This comment has been minimized.

Show comment
Hide comment
@haroldSanchezb

haroldSanchezb Apr 26, 2014

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

haroldSanchezb commented Apr 26, 2014

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

@GustavoHahn

This comment has been minimized.

Show comment
Hide comment
@GustavoHahn

GustavoHahn Apr 27, 2014

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

GustavoHahn commented Apr 27, 2014

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

@stechico

This comment has been minimized.

Show comment
Hide comment
@stechico

stechico Apr 28, 2014

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

stechico commented Apr 28, 2014

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

@haroldSanchezb

This comment has been minimized.

Show comment
Hide comment
@haroldSanchezb

haroldSanchezb May 2, 2014

@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!

haroldSanchezb commented May 2, 2014

@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!

@cmdthe3rd

This comment has been minimized.

Show comment
Hide comment
@cmdthe3rd

cmdthe3rd 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?

cmdthe3rd 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

This comment has been minimized.

Show comment
Hide comment
@thibmaek

thibmaek Aug 14, 2014

Doesn't work in Safari with newest SoundCloud

thibmaek commented Aug 14, 2014

Doesn't work in Safari with newest SoundCloud

@Korayem

This comment has been minimized.

Show comment
Hide comment
@Korayem

Korayem Oct 11, 2014

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

Korayem commented Oct 11, 2014

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

@kjvarga

This comment has been minimized.

Show comment
Hide comment
@kjvarga

kjvarga Oct 19, 2014

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

kjvarga commented Oct 19, 2014

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

@aleemb

This comment has been minimized.

Show comment
Hide comment
@aleemb

aleemb Nov 9, 2014

Yup, broken now. Is there a quick fix?

aleemb commented Nov 9, 2014

Yup, broken now. Is there a quick fix?

@haroldSanchezb

This comment has been minimized.

Show comment
Hide comment
@haroldSanchezb

haroldSanchezb Nov 17, 2014

Ok, i will check tonight

haroldSanchezb commented Nov 17, 2014

Ok, i will check tonight

@kjvarga

This comment has been minimized.

Show comment
Hide comment
@kjvarga

kjvarga Dec 1, 2014

Anything to report?

kjvarga commented Dec 1, 2014

Anything to report?

@Smithienious

This comment has been minimized.

Show comment
Hide comment
@Smithienious

Smithienious Nov 3, 2016

Time to give this an update?

Smithienious commented Nov 3, 2016

Time to give this an update?

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