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.

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.

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.

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.

Owner

duncanbeevers commented Apr 1, 2012

Added a minified version to the repo

@felixfischer

This comment has been minimized.

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.

Owner

duncanbeevers commented May 8, 2012

@felixfischer Thanks

@mcnemesis

This comment has been minimized.

mcnemesis commented Nov 13, 2012

This is one awesome!

@mcnemesis

This comment has been minimized.

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.

xristouz commented Nov 30, 2012

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

@incace

This comment has been minimized.

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.

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.

Owner

duncanbeevers commented Dec 27, 2012

Updated to work with Soundcloud Next.

@Technowise

This comment has been minimized.

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.

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.

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.

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.

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.

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.

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.

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.

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.

stechico commented Apr 28, 2014

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

@haroldSanchezb

This comment has been minimized.

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.

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.

thibmaek commented Aug 14, 2014

Doesn't work in Safari with newest SoundCloud

@Korayem

This comment has been minimized.

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.

kjvarga commented Oct 19, 2014

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

@aleemb

This comment has been minimized.

aleemb commented Nov 9, 2014

Yup, broken now. Is there a quick fix?

@haroldSanchezb

This comment has been minimized.

haroldSanchezb commented Nov 17, 2014

Ok, i will check tonight

@kjvarga

This comment has been minimized.

kjvarga commented Dec 1, 2014

Anything to report?

@Smithienious

This comment has been minimized.

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