Last active
October 16, 2025 09:56
-
-
Save webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 to your computer and use it in GitHub Desktop.
Revisions
-
webketje revised this gist
Jan 5, 2024 . 3 changed files with 20 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,9 +5,7 @@ Adds a 'Download' button to all single track views.  ## Features * No third-party embeds, redirects or ads, directly uses the Soundcloud API. * Works with ad-blocker on. @@ -16,4 +14,9 @@ Features: * Responsive, blends in with Soundcloud style. * To enable debug logging, set `debug: true` at the start of the userscript. ## Caveats * Soundcloud Go+ tracks will only download the 30 seconds preview sample. * Some tracks on Soundcloud are only provided as AES-encrypted [HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) playlist files. Soundcloud Downloader Clean is not able to download these and will instead display a modal with links to third-party Soundcloud downloaders:  This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,9 +1,16 @@ 2024-01-05 - v1.0.0 - feat: download button on HLS tracks will open a modal with third-party services - fix: don't display download button on user sets - fix: wait for soundActions bar to render for 5s - added: error log formatting - Updated README.md to include caveats - Reverse changelog to most recent first 2020-01-14 - v0.2.1 - Removed unnecessary dependency - Added changelog 2020-01-14 - v0.2 - Updated to Soundcloud API v2 - Use Soundcloud download button style - Updated screenshot and readme 2019-11-14 - v0.1 - Initial release This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ // ==UserScript== // @name Soundcloud Downloader Clean // @namespace https://openuserjs.org/users/webketje // @version 1.0.0 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button in the toolbar of all single track views. // @author webketje // @license MIT -
webketje revised this gist
Jan 4, 2024 . 1 changed file with 93 additions and 21 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -13,7 +13,7 @@ // @noframes // @match https://soundcloud.com/* // @grant unsafeWindow // @require https://cdn.jsdelivr.net/npm/[email protected].5/dist/FileSaver.min.js // ==/UserScript== /* globals saveAs */ @@ -22,7 +22,6 @@ 'use strict'; var win = unsafeWindow || window; var containerSelector = '.soundActions.sc-button-toolbar .sc-button-group'; var scdl = { @@ -32,6 +31,90 @@ modalId: 'scdl-third-party-modal' }; var labels = ({ en: { download: 'Download', downloading: 'Downloading', copy: 'Copy', copy_success: 'Copied to clipboard', copy_failure: 'Failed to copy to clipboard!', close: 'Close', modal_title: 'could not download this track. Use one of these third-party services instead?' }, es: { download: 'Descargar', downloading: 'Descargando..', copy: 'Copiar', copy_success: 'Copiada al portapapeles', copy_failure: '¡No se pudo copiar al portapapeles!', close: '', modal_title: 'no se pudo descargar esta banda sonora. ¿Utilizar uno de estos servicios de terceros en su lugar?' }, fr: { download: 'Télécharger', downloading: 'Téléchargement..', copy: 'Copier', copy_success: 'Copié dans le presse-papiers!', copy_failure: 'Échec de la copie dans le presse-papiers !', close: 'Fermer', modal_title: 'ne peut pas télécharger ce fichier. Utiliser l’un de ces services tiers ?' }, nl: { download: 'Downloaden', downloading: 'Downloaden..', copy: 'Kopiëren', copy_success: 'Naar klembord gekopieerd!', copy_failure: 'Kopiëren naar klembord mislukt!', close: 'Sluiten', modal_title: 'kon dit bestand niet downloaden. Een van deze externe diensten gebruiken?' }, de: { download: 'Herunterladen', downloading: 'Herunterladen..', copy: 'Kopieren', copy_success: 'In die Zwischenablage kopiert', copy_failure: 'Kopieren in die Zwischenablage fehlgeschlagen!', close: 'Schließen', modal_title: 'konnte diesen Sound nicht herunterladen. Nutzen Sie stattdessen einen dieser Drittanbieterdienste?' }, pl: { download: 'Ściągnij', downloading: 'Ściąganie..', copy: 'Kopiuj', copy_success: 'Skopiowano do schowka', copy_failure: 'Nie udało się skopiować do schowka!!', close: 'Zamknij', modal_title: 'nie udało się pobrać tego utworu. Zamiast tego skorzystać z jednej z usług stron trzecich?' }, it: { download: 'Scaricare', downloading: 'Scaricando..', copy: 'Copia', copy_success: 'Copiato negli appunti', copy_failure: 'Impossibile copiare negli appunti!', close: 'Chiudi', modal_title: 'non è stato possibile scaricare questo suono. Utilizzi invece uno di questi servizi di terze parti?' }, pt_BR: { download: 'Baixar', downloading: 'Baixando..', copy: 'Copiar', copy_success: 'Copiado para a área de transferência', copy_failure: 'Falha ao copiar para a área de transferência!!', close: 'Fechar', modal_title: 'não foi possível baixar este som. Usar um desses serviços de terceiros?' }, sv: { download: 'Ladda ner', downloading: 'Laddar ner..', copy: 'Kopiera', copy_success: 'Kopierat till urklipp', copy_failure: 'Det gick inte att kopiera till urklipp!', close: 'Stäng', modal_title: 'han kunde inte ladda ner det här ljudet. Använd någon av dessa tredjepartstjänster istället?' } })[document.documentElement.lang || 'en'] /** * @desc Log to console only if debug is true */ @@ -117,32 +200,21 @@ }; scdl.button = { download: function(e) { e.preventDefault(); var dlButton = document.getElementById(scdl.dlButtonId) if (dlButton) { dlButton.textContent = labels.downloading; } setTimeout(function() { saveAs(e.target.href, e.target.dataset.title); if (dlButton) { dlButton.textContent = labels.download; } }, 100) }, render: function(href, title, onClick) { var label = labels.download; var a = document.createElement('a'); a.className = "sc-button sc-button-medium sc-button-responsive sc-button-download"; a.href = href; @@ -194,17 +266,17 @@ const html = [ '<div class="modal g-z-index-modal-background g-opacity-transition g-z-index-overlay modalWhiteout showBackground g-backdrop-filter-grayscale" style="outline: none; padding-right: 0px; display: flex; justify-content: center;" tabindex="-1" id="scdl-third-party-modal">', '<div class="modal__modal sc-border-box g-z-index-modal-content transparentBackground" style="height: auto;">', '<button type="button" title="' + labels.close + '" class="modal__closeButton">' + labels.close + '</button>', '<div class="modal__content"><div class="tabs"><div class="tabs__content"><div class="tabs__contentSlot" style="display: block;"><article class="shareContent">', '<div class="publicShare"><section class="g-modal-section sc-clearfix sc-pt-2x">', '<h2 class="sc-orange">Soundcloud Downloader Clean ' + labels.modal_title + '</h2>', '</section><section class="g-modal-section sc-clearfix sc-pt-2x">', '<h3 style="margin-bottom: 0.5rem;">' + labels.download + ' <em>' + title + '</em> via: </h3>', this.providers.map(p => ['<div><a href="', win.atob(p), '" target="_blank" style="display: inline-block; font-size: 14px; padding: 0.25rem 0;">', win.atob(p), '</a></div>'].join('')).join(''), '<div class="shareLink sc-clearfix publicShare__link sc-pt-2x m-showPositionOption" style="margin-top: 1rem;">', '<label for="shareLink__field" style="margin-right:0.5rem;">Link</label>', '<input type="text" value="' + win.location.href + '" class="shareLink__field sc-input" id="shareLink__field" readonly="readonly">', '<button class="sc-button sc-button-copy">' + labels.copy + '</button>', '<span class="sc-copy-feedback" style="margin-left: 1rem;"></span>', '</div>', '</section></div></article></div></div></div></div></div></div>' -
webketje revised this gist
Dec 27, 2023 . 2 changed files with 75 additions and 4 deletions.There are no files selected for viewing
LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,12 +22,14 @@ 'use strict'; var win = unsafeWindow || window; var lang = document.documentElement.lang var containerSelector = '.soundActions.sc-button-toolbar .sc-button-group'; var scdl = { debug: false, client_id: '', dlButtonId: 'scdlc-btn', modalId: 'scdl-third-party-modal' }; /** @@ -128,10 +130,19 @@ }, download: function(e) { e.preventDefault(); var dlButton = document.getElementById(scdl.dlButtonId) if (dlButton) { dlButton.textContent = 'Downloading...' } setTimeout(function() { saveAs(e.target.href, e.target.dataset.title); if (dlButton) { dlButton.textContent = scdl.button.label[lang] } }, 0) }, render: function(href, title, onClick) { var label = scdl.button.label[lang]; var a = document.createElement('a'); a.className = "sc-button sc-button-medium sc-button-responsive sc-button-download"; a.href = href; @@ -172,6 +183,62 @@ } }; scdl.modal = { providers: [ 'aHR0cHM6Ly9zY2xvdWRkb3dubG9hZGVyLm5ldA==', 'aHR0cHM6Ly93d3cuc291bmRjbG91ZG1wMy5vcmc=', 'aHR0cHM6Ly9zb3VuZGNsb3VkbWUuY29t' ], render: function(title) { var temp = document.createElement('div'), self = this const html = [ '<div class="modal g-z-index-modal-background g-opacity-transition g-z-index-overlay modalWhiteout showBackground g-backdrop-filter-grayscale" style="outline: none; padding-right: 0px; display: flex; justify-content: center;" tabindex="-1" id="scdl-third-party-modal">', '<div class="modal__modal sc-border-box g-z-index-modal-content transparentBackground" style="height: auto;">', '<button type="button" title="Close" class="modal__closeButton">Close</button>', '<div class="modal__content"><div class="tabs"><div class="tabs__content"><div class="tabs__contentSlot" style="display: block;"><article class="shareContent">', '<div class="publicShare"><section class="g-modal-section sc-clearfix sc-pt-2x">', '<h2 class="sc-orange">Soundcloud Downloader Clean could not download this track. Use one of these third-party services instead?</h2>', '</section><section class="g-modal-section sc-clearfix sc-pt-2x">', '<h3 style="margin-bottom: 0.5rem;">Download <em>' + title + '</em> via: </h3>', this.providers.map(p => ['<div><a href="', win.atob(p), '" target="_blank" style="display: inline-block; font-size: 14px; padding: 0.25rem 0;">', win.atob(p), '</a></div>'].join('')).join(''), '<div class="shareLink sc-clearfix publicShare__link sc-pt-2x m-showPositionOption" style="margin-top: 1rem;">', '<label for="shareLink__field" style="margin-right:0.5rem;">Link</label>', '<input type="text" value="' + win.location.href + '" class="shareLink__field sc-input" id="shareLink__field" readonly="readonly">', '<button class="sc-button sc-button-copy">Copy</button>', '<span class="sc-copy-feedback" style="margin-left: 1rem;"></span>', '</div>', '</section></div></article></div></div></div></div></div></div>' ].join('') temp.innerHTML = html var cnt = temp.firstElementChild cnt.addEventListener('click', function(e) { if (this === e.target || e.target.classList.contains('modal__closeButton')) { self.remove() } else if (e.target.classList.contains('sc-button-copy')) { navigator.clipboard.writeText(win.location.href) .then(function() { var f = cnt.querySelector('.sc-copy-feedback') f.innerHTML = '<span style="color: green;">Copied to clipboard!</span>' }, function(err) { log('Failed to write URL to the clipboard.', err) var f = cnt.querySelector('.sc-copy-feedback') f.innerHTML = '<span style="color: red;">Failed to copy to clipboard!</span>' }) } }) return cnt }, attach: function() { this.remove() document.body.appendChild(this.render.apply(this, arguments)) }, remove: function() { var modal = document.getElementById(scdl.modalId); if (modal) modal.parentNode.removeChild(modal); } } scdl.parseClientIdFromURL = function(url) { var search = /client_id=([\w\d]+)&*/; return url && url.match(search) && url.match(search)[1]; @@ -205,7 +272,11 @@ }, function onError() { log('%c No compatible media transcoding found.', 'color: #FF0000;'); scdl.button.attach('javascript:void(0);', 'None', function() { var title = document.querySelector('.soundTitle__title') var artist = document.querySelector('.soundTitle__username') scdl.modal.attach([artist.textContent.trim(), '-', title.textContent.trim()].join(' ')) }) } ); }; -
webketje revised this gist
Dec 27, 2023 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -154,12 +154,12 @@ var intv = setInterval(function() { var f = document.querySelector(containerSelector) iterations++ if (f && !document.getElementById(scdl.dlButtonId)) { f.insertAdjacentElement('beforeend', self.render.apply(self, args)); log('Attaching download button to element:', f) clearInterval(intv) // stop after trying to find the element for 5s } else if (iterations === 50) { log('%c Couldn\'t find element "' + containerSelector + '" after 2 seconds', 'color: #FF0000;') clearInterval(intv) } @@ -185,7 +185,7 @@ scdl.load = function(url) { // for now only make available for single track pages if (/^(\/(you|stations|discover|stream|upload|search|settings|.+?\/sets))/.test(win.location.pathname)) { scdl.button.remove(); return; } -
webketje revised this gist
Dec 26, 2023 . 1 changed file with 20 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -23,6 +23,7 @@ var win = unsafeWindow || window; var containerSelector = '.soundActions.sc-button-toolbar .sc-button-group'; var scdl = { debug: false, client_id: '', @@ -35,8 +36,8 @@ function log() { var stamp = new Date().toLocaleString(), args = [].slice.call(arguments), prefix = ['SCDLC', stamp, '-'].join(' '); if (scdl.debug) console.log.apply(console, [prefix + args[0]].concat(args.slice(1))); }; /** @@ -66,8 +67,6 @@ }; scdl.getMediaURL = function(json, onresolve, onerror) { if (json.media && json.media.transcodings) { var found = json.media.transcodings.filter(function(tc) { return tc.format && tc.format.protocol === 'progressive'; @@ -149,11 +148,22 @@ return a; }, attach:function() { var args = arguments, self = this, iterations = 0 // account for rendering delays var intv = setInterval(function() { var f = document.querySelector(containerSelector) iterations++ if (f) { f.insertAdjacentElement('beforeend', self.render.apply(self, args)); log('Attaching download button to element:', f) clearInterval(intv) // stop after trying to find the element 20x } else if (iterations === 20) { log('%c Couldn\'t find element "' + containerSelector + '" after 2 seconds', 'color: #FF0000;') clearInterval(intv) } }, 100) }, remove: function() { var btn = document.getElementById(scdl.dlButtonId); @@ -194,6 +204,7 @@ } }, function onError() { log('%c No compatible media transcoding found.', 'color: #FF0000;'); scdl.button.remove(); } ); -
webketje revised this gist
Jan 13, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ // ==UserScript== // @name Soundcloud Downloader Clean // @namespace https://openuserjs.org/users/webketje // @version 0.2.1 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button in the toolbar of all single track views. // @author webketje // @license MIT -
webketje revised this gist
Jan 13, 2020 . 3 changed files with 11 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,5 +14,6 @@ Features: * Can be used without Soundcloud account or logged out. * Works with all Soundcloud languages. * Responsive, blends in with Soundcloud style. * To enable debug logging, set `debug: true` at the start of the userscript. **Note:** Soundcloud Go+ tracks will only download the 30 seconds preview sample. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ 2019-11-14 - v0.1 - Initial release 2020-01-14 - v0.2 - Updated to Soundcloud API v2 - Use Soundcloud download button style - Updated screenshot and readme 2020-01-14 - v0.2.1 - Removed unnecessary dependency - Added changelog This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,7 +14,6 @@ // @match https://soundcloud.com/* // @grant unsafeWindow // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js // ==/UserScript== /* globals saveAs */ @@ -25,7 +24,7 @@ var win = unsafeWindow || window; var containerSelector = '.soundActions.sc-button-toolbar .sc-button-group'; var scdl = { debug: false, client_id: '', dlButtonId: 'scdlc-btn' }; -
webketje revised this gist
Jan 13, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,7 +3,7 @@ An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views.  Adds a 'Download' button to all single-track views. -
webketje revised this gist
Jan 13, 2020 . 3 changed files with 72 additions and 21 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,18 @@ # Tampermonkey userscript - Soundcloud Downloader Clean An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views.  Adds a 'Download' button to all single-track views. Features: * No third-party embeds, redirects or ads, directly uses the Soundcloud API. * Works with ad-blocker on. * Can be used without Soundcloud account or logged out. * Works with all Soundcloud languages. * Responsive, blends in with Soundcloud style. **Note:** Soundcloud Go+ tracks will only download the 30 seconds preview sample. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,19 +1,20 @@ // ==UserScript== // @name Soundcloud Downloader Clean // @namespace https://openuserjs.org/users/webketje // @version 0.2 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button in the toolbar of all single track views. // @author webketje // @license MIT // @icon https://a-v2.sndcdn.com/assets/images/sc-icons/favicon-2cadd14bdb.ico // @homepageURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 // @supportURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6#comments // @updateURL https://openuserjs.org/meta/webketje/Soundcloud_Downloader_Clean.meta.js // @downloadURL https://openuserjs.org/install/webketje/Soundcloud_Downloader_Clean.user.js // @noframes // @match https://soundcloud.com/* // @grant unsafeWindow // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/polyfill.min.js // ==/UserScript== /* globals saveAs */ @@ -22,7 +23,12 @@ 'use strict'; var win = unsafeWindow || window; var containerSelector = '.soundActions.sc-button-toolbar .sc-button-group'; var scdl = { debug: true, client_id: '', dlButtonId: 'scdlc-btn' }; /** * @desc Log to console only if debug is true @@ -31,7 +37,7 @@ var stamp = new Date().toLocaleString(), args = [].slice.call(arguments), prefix = ['SCDLC', stamp, '-']; if (scdl.debug) console.log.apply(console, prefix.concat(args)); }; /** @@ -53,32 +59,60 @@ }; }; scdl.getTrackName = function(trackJSON) { return [ trackJSON.user.username, trackJSON.title ].join(' - '); }; scdl.getMediaURL = function(json, onresolve, onerror) { //if (json.download_url) return onresolve(json.download_url + '&client_id=' + scdl.client_id); //if (json.stream_url) return onresolve(json.stream_url + '&client_id=' + scdl.client_id); if (json.media && json.media.transcodings) { var found = json.media.transcodings.filter(function(tc) { return tc.format && tc.format.protocol === 'progressive'; })[0]; if (found) { var xhr = new XMLHttpRequest(); xhr.onload = function() { var result; try { result = JSON.parse(xhr.responseText); } catch (err) {} if (result && result.url) onresolve(result.url); else onerror(false); }; xhr.onerror = onerror; xhr.open('GET', found.url + '?client_id=' + scdl.client_id); xhr.send(); } else { onerror(false); } } else { onerror(false); } }; scdl.getStreamURL = function(url, onresolve, onerror) { var xhr = new XMLHttpRequest(); xhr.onload = function() { var trackJSON = JSON.parse(xhr.responseText); scdl.getMediaURL(trackJSON, function resolve(url) { onresolve({ stream_url: url, track_name: scdl.getTrackName(trackJSON) }); }, function reject() { onerror(false); }) }.bind(this); xhr.onerror = function() { onerror(false); }; xhr.open('GET', 'https://api-v2.soundcloud.com/resolve?url=' + encodeURIComponent(url) + '&client_id=' + this.client_id); xhr.send(); }; @@ -101,23 +135,26 @@ render: function(href, title, onClick) { var label = scdl.button.label[document.documentElement.lang]; var a = document.createElement('a'); a.className = "sc-button sc-button-medium sc-button-responsive sc-button-download"; a.href = href; a.id = scdl.dlButtonId; a.textContent = label; a.title = label; a.dataset.title = title + '.mp3'; a.setAttribute('download', title + '.mp3'); a.target = '_blank'; a.onclick = onClick; a.style.marginLeft = '5px'; a.style.cssFloat = 'left'; a.style.border = '1px solid orangered'; return a; }, attach:function() { this.remove(); var f = document.querySelector(containerSelector); log('Attaching download button', f); if (f) f.insertAdjacentElement('beforeend', this.render.apply(this, arguments)); }, remove: function() { var btn = document.getElementById(scdl.dlButtonId); @@ -157,7 +194,9 @@ ); } }, function onError() { scdl.button.remove(); } ); }; @@ -169,7 +208,7 @@ scdl.load(win.location.href); } }); if (scdl.debug) win.scdl = scdl; scdl.getClientID(function(id) { log('Found Soundcloud client id:', id, '. Initializing...'); scdl.client_id = id; LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed. -
webketje revised this gist
Nov 11, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,4 +3,4 @@ An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views.  -
webketje revised this gist
Nov 11, 2019 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,6 @@ # Tampermonkey userscript - Soundcloud Downloader Clean An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views.  -
webketje revised this gist
Nov 11, 2019 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,12 +2,14 @@ // @name Soundcloud Downloader Clean // @namespace https://openuserjs.org/users/webketje // @version 0.1.0 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button in the toolbar of all single track views. // @author webketje // @license MIT // @icon https://a-v2.sndcdn.com/assets/images/sc-icons/favicon-2cadd14bdb.ico // @homepageURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 // @supportURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 // @updateURL https://openuserjs.org/meta/webketje/Soundcloud_Downloader_Clean.meta.js // @downloadURL https://openuserjs.org/install/webketje/Soundcloud_Downloader_Clean.user.js // @noframes // @match https://soundcloud.com/* // @grant unsafeWindow -
webketje revised this gist
Nov 11, 2019 . 1 changed file with 6 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,9 +1,13 @@ // ==UserScript== // @name Soundcloud Downloader Clean // @namespace https://openuserjs.org/users/webketje // @version 0.1.0 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views. // @author webketje // @license MIT // @homepageURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 // @supportURL https://gist.github.com/webketje/8cd2e6ae8a86dbe0533c5d2c612c42c6 // @updateURL https://openuserjs.org/meta/webketje/Soundcloud_Downloader_Clean.meta.js // @noframes // @match https://soundcloud.com/* // @grant unsafeWindow -
webketje created this gist
Nov 11, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,4 @@ # Tampermonkey userscript - Soundcloud Downloader Clean An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,172 @@ // ==UserScript== // @name Soundcloud Downloader Clean // @namespace http://tampermonkey.net/ // @version 0.1 // @description An ad-less, multilingual, clean Soundcloud downloader with robust code. Adds a 'Download' button to all single track views. // @author webketje // @noframes // @match https://soundcloud.com/* // @grant unsafeWindow // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js // ==/UserScript== /* globals saveAs */ (function() { 'use strict'; var win = unsafeWindow || window; var containerSelector = '.listenEngagement__footer .sc-button-toolbar'; /** * @desc Log to console only if debug is true */ function log() { var stamp = new Date().toLocaleString(), args = [].slice.call(arguments), prefix = ['SCDLC', stamp, '-']; scdl.debug && console.log(prefix.concat(args).join(' ')); }; /** * @desc There is no other way to retrieve a Soundcloud client_id than by spying on existing requests. * We temporarily patch the XHR.send method to retrieve the url passed to it. * @param restoreIfTrue - restores the original prototype method when true is returned * @param onRestore - a function to exec when the restoreIfTrue condition is met */ function patchXHR(restoreIfTrue, onRestore) { var originalXHR = win.XMLHttpRequest.prototype.open; win.XMLHttpRequest.prototype.open = function() { originalXHR.apply(this, arguments); var restore = restoreIfTrue.apply(this, arguments); if (restore) { win.XMLHttpRequest.prototype.open = originalXHR; onRestore(restore); } }; }; var scdl = { debug: false, client_id: '', dlButtonId: 'scdlc-btn' }; scdl.getTrackName = function(trackJSON) { return [ trackJSON.user.username, trackJSON.title ].join(' - '); }; scdl.getStreamURL = function(url, onresolve, onerror) { var xhr = new XMLHttpRequest(); xhr.onload = function() { var trackJSON = JSON.parse(xhr.responseText); onresolve(trackJSON.errors || !trackJSON.stream_url ? false : { stream_url: trackJSON.stream_url + '?client_id=' + this.client_id, track_name: this.getTrackName(trackJSON) }); }.bind(this); xhr.onerror = function() { onerror(false); }; xhr.open('GET', 'https://api.soundcloud.com/resolve?url=' + encodeURIComponent(url) + '&client_id=' + this.client_id); xhr.send(); }; scdl.button = { label: { en: 'Download', es: 'Descargar', fr: 'Télécharger', nl: 'Download', de: 'Download', pl: 'Ściągnij', it: 'Scaricare', pt_BR: 'Baixar', sv: 'Ladda ner' }, download: function(e) { e.preventDefault(); saveAs(e.target.href, e.target.dataset.title); }, render: function(href, title, onClick) { var label = scdl.button.label[document.documentElement.lang]; var a = document.createElement('a'); a.className = "sc-button"; a.href = href; a.id = scdl.dlButtonId; a.textContent = label; a.dataset.title = title + '.mp3'; a.setAttribute('download', title + '.mp3'); a.target = '_blank'; a.onclick = onClick; a.style.marginLeft = '5px'; a.style.cssFloat = 'left'; return a; }, attach:function() { this.remove(); var f = document.querySelector(containerSelector); if (f) f.insertAdjacentElement('afterend', this.render.apply(this, arguments)); }, remove: function() { var btn = document.getElementById(scdl.dlButtonId); if (btn) btn.parentNode.removeChild(btn); } }; scdl.parseClientIdFromURL = function(url) { var search = /client_id=([\w\d]+)&*/; return url && url.match(search) && url.match(search)[1]; }; scdl.getClientID = function(onClientIDFound) { patchXHR(function(method, url) { return scdl.parseClientIdFromURL(url); }, onClientIDFound); }; scdl.load = function(url) { // for now only make available for single track pages if (/^(\/(you|stations|discover|stream|upload|search|settings))/.test(win.location.pathname)) { scdl.button.remove(); return; } scdl.getStreamURL(url, function onSuccess(result) { if (!result) { scdl.button.remove(); } else { log('Detected valid Soundcloud artist track URL. Requesting info...'); scdl.button.attach( result.stream_url, result.track_name, scdl.button.download ); } }, scdl.button.remove ); }; // patch front-end navigation ['pushState','replaceState','forward','back','go'].forEach(function(event) { var tmp = win.history.pushState; win.history[event] = function() { tmp.apply(win.history, arguments); scdl.load(win.location.href); } }); scdl.getClientID(function(id) { log('Found Soundcloud client id:', id, '. Initializing...'); scdl.client_id = id; scdl.load(win.location.href); }); })();