Created
May 12, 2019 22:34
-
-
Save hinell/72343f9d98d311d205a6335c91ec9ac2 to your computer and use it in GitHub Desktop.
This file contains 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 characters
/******************** | |
Name : SC.getDonwloadLinks | |
Version : 0.1.0 | |
Last-Modified : 13.05.19 | |
Description : Snippets extracts track's urls from the page and inserts direct download link | |
**********************/ | |
console.clear(); | |
// The clientId may be gotten from http request uri | |
// Usage: urlInstance.searchParams.set(`client_id`, clientId) | |
var clientId = `98bwvJm1CyzjAZCeNbMb7RZKWoS3zvEe`; | |
// Helpers | |
HTMLElement.prototype.$ = HTMLElement.prototype.querySelector | |
HTMLElement.prototype.$$= HTMLElement.prototype.querySelectorAll | |
NodeList.prototype.map = Array.prototype.map; | |
String.prototype.contains = function(str){ return new RegExp(str).test(this) } | |
/* | |
* Makes clipboard (temporary buffer) managment easier | |
* Usage: new Clipspace().copy('foo') // copies 'foo' string to the clipboard | |
**/ | |
var Clipspace = class { | |
static version = '1.0.0'; | |
constructor (container) { | |
this.container = container || document.body; | |
this.id = 'clipboard-area'; | |
this.el = this.container.querySelector('#'+this.id); | |
if (!this.el) { | |
this.el = document.createElement('textarea'); | |
this.container.appendChild(this.el); | |
} | |
this.el.style.position = 'absolute' | |
this.el.style.top = '-9999px'; | |
this.el.contentEditable = true; | |
this.el.id = this.id; | |
} | |
copy(text) { | |
this.el.value = text | |
this.el.select(); | |
var result = document.execCommand('copy'); | |
this.el.blur(); | |
return result | |
} | |
} | |
/* | |
* | |
* @return {Array.<Object>} -- where TrackInstance is following (the item's type's isn't complete): | |
**/ | |
var SCTracksFromJsonP = async function(){ | |
const scripts = Array.from(document.body.querySelectorAll(`script`)); | |
const dataSource = scripts.pop(); | |
const data = []; | |
const wbpckjsp = new Function(`webpackJsonp`,dataSource.textContent.replace(`n(e.id)`,`n(e.data[0])`)) | |
wbpckjsp(function(_, localDataStore){ | |
localDataStore[0](null, null, (e) => { | |
data.push(e) | |
}); | |
}); | |
let tracks = data.reduce(function(arr, e){ | |
if (e.kind === "playlist") { | |
return arr.concat(e.tracks) | |
}; | |
if (e.kind === "track") { | |
arr.push(e) | |
return arr | |
}; | |
return arr | |
}, []); | |
// Fetch direct urls to the file sound resources | |
// Make sure that argument of the all(...) here is array of promises | |
return await Promise.all(tracks.map(async function(track){ | |
if (track.download_url) { | |
return track | |
} | |
if (!(track.media && track.media.transcodings)) { return track } | |
var transcodings = track.media.transcodings.map(async function (trans) { | |
trans.url = new URL(trans.url); | |
trans.url.searchParams.set(`client_id`, clientId); | |
var response = await fetch(trans.url); | |
if (!response.ok) { throw new Error(`track fetching transcoding url failed: ${response.status} ${response.statusText }`) } | |
if (response.status === 200) { | |
// if fetched successfully then return parsed url | |
var mp3Url = await response.text(); | |
var urlObj = JSON.parse(mp3Url); | |
trans.directUrl = urlObj.url; | |
} | |
return trans | |
}); | |
track.media.transcodings = await Promise.all(transcodings) | |
return track | |
})) | |
}; | |
// Creates link element | |
var Link = function({ textDisplay, url, downloadFileName }) { | |
console.log('Inserting link!') | |
if (!url) { throw new Error('Url required!') } | |
var link = document.createElement('a'); | |
link.href = url; | |
link.download = downloadFileName || 'New File'; | |
link.textContent = textDisplay; | |
link.title = 'Song download link'; | |
link.target = '_blank'; | |
return link | |
} | |
var clipspace = new Clipspace(); | |
// Scraps tracks ulrs from the current page | |
var initDownloadFileButton = function (tracks) { | |
var track = tracks[0]; | |
var trans = track.media.transcodings; | |
url = trans[1].directUrl || trans[0].directUrl || trans[2].directUrl || track.download_url; | |
var fileName = `${track.user.username} - ${track.title}`; | |
// Initialize link | |
window._previous_dnload_button && window._previous_dnload_button.remove(); | |
let link = Link({ | |
textDisplay: 'Steal song!', | |
url : url, | |
downloadFileName: fileName, | |
}); | |
link.addEventListener('contextmenu', function(){ | |
clipspace.copy(fileName); | |
}) | |
window._previous_dnload_button = link; | |
link.className = 'soundActions__purchaseLink sc-truncate sc-buylink sc-buylink-responsive sc-buylink-medium sc-buylink-default'; | |
let actionpanel = document.body.$('.listenEngagement__actions .sc-button-group') // SoundCloud | |
|| document.body.$('.playlist-actions') | |
|| document.body.$('.collectionSection__top') // | |
|| document.body.$('#watch7-user-header') // YouTube | |
if (actionpanel) { | |
actionpanel.appendChild(link); | |
} | |
}; | |
;(async function () { | |
var tracks; | |
try { | |
tracks = await SCTracksFromJsonP(); | |
if (tracks.length === 1) { | |
initDownloadFileButton(tracks); | |
} else { | |
}; | |
console.log(tracks) | |
} catch (e) { | |
console.log('Total failure!') | |
console.error(e) | |
} | |
console.log(tracks.map(t => t.id).join(',')) | |
console.log(tracks) | |
})() | |
// donwloadCb(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment