// ==UserScript== // @name Disney+ Audio Downloader // @name:fr Disney+ Audio Downloader // @namespace https://greasyfork.org/fr/users/572942-stegner // @homepage https://greasyfork.org/fr/scripts/405994-disney-audio-downloader // @description Download audio from Disney+ // @description:fr Télécharger l'audio de Disney+ // @version 1.0 // @author stegner // @match https://www.disneyplus.com/* // @grant none // @downloadURL none // ==/UserScript== function start(){ if (typeof document.initaudio !== "undefined") { document.initaudio(); } if (typeof document.initsub !== "undefined") { document.initsub(); } listensend(); document.handleinterval = setInterval(buttonhandle,100); } window.onload = start; document.initaudio = function(){ document.audios = new Array(); document.content = new Uint8Array(); document.baseurl=""; document.m3u8found=false; document.wait=false; document.filename=""; document.episode=""; document.audioid=null; // Add download icon document.styleSheets[0].addRule('#audioTrackPicker > div:before','content:"";color:#fff;padding-right:35px;padding-top:2px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAIGNIUk0AAHonAACAgwAA+mQAAIDSAAB2hgAA7OkAADmeAAAV/sZ+0zoAAAE4SURBVHja1JS7LkRRFIa/M6aYRCEuCUEUgihFBolGVGqiFY1ConfpNB7CiygUGm8hOiMukwiCCMl8mj2xc5yZM8M0/mTlrLP2v75zydo7UclRL3AGlIAl4L6ZuUC+5oEZYBoo55lbAdai/LPTwFongG3pfwI3gZ3ovhjlXVG+BWz/6FbjKPuto1CbjWoLobYf1RZjRho4pt5F5g11QK2F6FFXo/UXdbwZEHVQvY2aztWPECdR/TkNawREHUpB03pSJ7J6Cf9gL3xOvDiiXmfAHtSplLek7qorqI/BeJjxxFG1kgNDPQjrn4VoLPozRqgCzAGXwFXILzJ8w+H6XgRegW7grcGs3gCTOfP8UgfGg139wwapxrugDl0H+oCkTZjAcsiTxBaO7HZUBI6BtfCmv4Un4aw8/RoA7wq6AO4uOhAAAAAASUVORK5CYII=) no-repeat right;width:20px;height:18px;position:absolute;top:6px;right:10px;opacity:0.6;cursor:pointer;'); document.styleSheets[0].addRule('#audioTrackPicker > div:hover:before','opacity:1;'); } // Catch M3U8 files function listensend(){ XMLHttpRequest.prototype.realSend = XMLHttpRequest.prototype.send; var newSend = function(vData) { if(!document.m3u8found) { try { var objData = JSON.parse(vData); if(typeof objData.url !== 'undefined') { if(objData.url.indexOf(".m3u8")>0 && document.url!=objData.url) { // m3u8 url document.url = objData.url; document.langs = []; document.baseurl=document.url.substring(0,document.url.lastIndexOf('/')+1); document.m3u8found=true; getpagecontent(m3u8loaded,document.url); } } } catch (error) {} } this.realSend(vData); } XMLHttpRequest.prototype.send = newSend; } function m3u8loaded(response) { if (typeof document.m3u8sub !== "undefined") { document.m3u8sub(response); } if (typeof document.m3u8audio !== "undefined") { document.m3u8audio(response); } document.wait=false; } document.m3u8audio = function(response){ var lines = response.split('#'); var found = false; if(lines[2].indexOf("EXT-X-INDEPENDENT-SEGMENTS")==0){ // Audio tracks list var quality=null; lines.forEach(function(line) { if(line.indexOf('TYPE=AUDIO')>0) { // audio infos if(line.indexOf('GROUP-ID="eac-3"')>0 && (quality==null||quality=="eac-3")){ quality="eac-3"; document.audios.push(linetoarray(line)); } else if(line.indexOf('GROUP-ID="aac-128k"')>0 && (quality==null||quality=="aac-128k")){ quality="aac-128k"; document.audios.push(linetoarray(line)); } else if(line.indexOf('GROUP-ID="aac-64k"')>0 && (quality==null||quality=="aac-64k")){ quality="aac-64k"; document.audios.push(linetoarray(line)); } } }); } else if(response.indexOf(".mp4a")>0) { //console.log(lines); downloadmp4a(response); } } function downloadmp4a(m3u8data){ var lines = m3u8data.split(/\r?\n/g); var mapfound=false; var percent; var i=0; document.downloadInterval = setInterval(function () { var line = lines[i]; var url=null; if(line!=null){ var uri = document.audios[document.audioid].URI; if(line.indexOf("map.mp4a")>0 && !mapfound){ // Get mp4a map url = document.baseurl+uri.substring(0,uri.lastIndexOf("/")+1)+line.substring(line.indexOf('"')+1,line.lastIndexOf('"')); mapfound=true; } else if(line.indexOf("_000.mp4a")>0 && line.indexOf("DUB_CARD")<0){ // Get mp4a data url = document.baseurl+uri.substring(0,uri.lastIndexOf("/")+1)+line; } if(url!=null && !document.wait){ // Download file getpagecontent(mp4aloaded,url,true); document.wait=true; i++; } else if(url==null){ // Skip line i++; } if(percent!=Math.round((i/lines.length)*100)){ percent=Math.round((i/lines.length)*100); document.styleSheets[0].addRule('#audioTrackPicker > div:nth-child('+(document.audioid+1)+'):before','content:"'+percent+'%";'); } } else { // Download finished clearInterval(document.downloadInterval); document.styleSheets[0].addRule('#audioTrackPicker > div:nth-child('+(document.audioid+1)+'):before','content:"";'); exportblob(document.content, 'video/mp4'); document.content=new Uint8Array(); } },10); } function mp4aloaded(response) { document.content=appendbuffer(document.content,response); document.wait=false; } function linetoarray(line) { var result = new Array(); var values = line.split(','); values.forEach(function(value) { var data = value.replace(/\r\n|\r|\n/g,'').split('='); if(data.length>1) { var key = data[0]; var content = data[1].replace(/"/g,''); result[key]=content; } }); return result; } function buttonhandle() { var buttons = document.getElementsByClassName("control-icon-btn"); if(buttons.length>0) { if (typeof document.clickhandlesub !== "undefined") { document.clickhandlesub(); } if (typeof document.clickhandleaudio !== "undefined") { document.clickhandleaudio(); } document.filename = document.getElementsByClassName("title-field")[0].innerText; if(document.getElementsByClassName("subtitle-field").length>0) { document.episode = document.getElementsByClassName("subtitle-field")[0].innerText } } if(document.oldlocation!=window.location.href&&document.oldlocation!=null) { // location changed document.m3u8found=false; document.audios = []; document.langs = []; } document.oldlocation=window.location.href; } document.clickhandleaudio = function() { var picker = document.getElementsByClassName("options-picker audio-track-picker"); picker[0].childNodes.forEach(function(child) { var element = child.childNodes[0]; var lang = element.childNodes[1].innerHTML; if(child.onclick==null) { child.onclick = selectaudio; } }); } function selectaudio(e) { var width = this.offsetWidth; // Check click position if(e.layerX>=width-30&&e.layerX<=width-10&&e.layerY>=5&&e.layerY<=25){ // Download sub download(this.childNodes[0].childNodes[1].innerHTML); // Cancel selection return false; } } function download(langname) { if(!document.wait){ var count=0; document.audios.forEach(function(audio) { if(audio.NAME==langname) { document.audioid=count; getpagecontent(m3u8loaded,document.baseurl+audio.URI); document.wait=true; } count++; }); if(count==0){ alert("An error has occurred, please reload the page."); } } } function getpagecontent(callback,url,binary) { var http=new XMLHttpRequest(); http.open("GET", url, true); if(binary){ http.responseType = "arraybuffer"; } http.onloadend = function() { if(http.readyState == 4 && http.status == 200) { if(binary){ callback(http.response); } else { callback(http.responseText); } } else if (http.status === 404) { callback(""); } } http.send(); } function appendbuffer(buffer1, buffer2) { var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); tmp.set(new Uint8Array(buffer2), buffer1.byteLength); return tmp; }; // Save file as arraybuffer function exportblob(data, mimeType) { var blob, url; var output = document.filename; if(document.episode!="") { output+= " - "+document.episode.replace(':',''); } output += "."+document.audios[document.audioid].LANGUAGE; output += ".mp4"; blob = new Blob([data], { type: mimeType }); url = window.URL.createObjectURL(blob); downloadurl(url, output); setTimeout(function() { return window.URL.revokeObjectURL(url); }, 1000); }; function downloadurl(data, fileName) { var a; a = document.createElement('a'); a.href = data; a.download = fileName; document.body.appendChild(a); a.style = 'display: none'; a.click(); a.remove(); };