Disney+ Subtitles Downloader

Download subtitles from Disney+

נכון ליום 27-05-2020. ראה הגרסה האחרונה.

// ==UserScript==
// @name           Disney+ Subtitles Downloader
// @name:fr        Disney+ Subtitles Downloader
// @namespace      https://greasyfork.org/scripts/404223-disney-subtitles-downloader
// @description    Download subtitles from Disney+
// @description:fr Télécharger les sous-titres de Disney+
// @version        1.2
// @author         stegner
// @match          https://www.disneyplus.com/*
// @grant          none
// ==/UserScript==

window.onload = function() {
    XMLHttpRequest.prototype.realSend = XMLHttpRequest.prototype.send;
    document.langs = new Array();
    document.segments = "";
    document.forced=false;
    document.wait=false;
    var m3u8found=false;
    var segid=0;
    var url;
    var vtturl;
    var filename="";
    var episode="";
    var oldlocation;

    // Add download icon
    document.styleSheets[0].addRule('#subtitleTrackPicker > div:before','content:"";background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAIGNIUk0AAHonAACAgwAA+mQAAIDSAAB2hgAA7OkAADmeAAAV/sZ+0zoAAAE4SURBVHja1JS7LkRRFIa/M6aYRCEuCUEUgihFBolGVGqiFY1ConfpNB7CiygUGm8hOiMukwiCCMl8mj2xc5yZM8M0/mTlrLP2v75zydo7UclRL3AGlIAl4L6ZuUC+5oEZYBoo55lbAdai/LPTwFongG3pfwI3gZ3ovhjlXVG+BWz/6FbjKPuto1CbjWoLobYf1RZjRho4pt5F5g11QK2F6FFXo/UXdbwZEHVQvY2aztWPECdR/TkNawREHUpB03pSJ7J6Cf9gL3xOvDiiXmfAHtSplLek7qorqI/BeJjxxFG1kgNDPQjrn4VoLPozRqgCzAGXwFXILzJ8w+H6XgRegW7grcGs3gCTOfP8UgfGg139wwapxrugDl0H+oCkTZjAcsiTxBaO7HZUBI6BtfCmv4Un4aw8/RoA7wq6AO4uOhAAAAAASUVORK5CYII=);width:20px;height:20px;position:absolute;top:6px;right:10px;cursor:pointer;');
    document.styleSheets[0].addRule('#subtitleTrackPicker > div:first-child:before','content:"";width:0px;height:0px;');

    var newSend = function(vData) {
        if(!m3u8found) {
            try {
                var objData = JSON.parse(vData);
                if(typeof objData.url !== 'undefined') {
                    if(objData.url.indexOf(".m3u8")>0 && url!=objData.url) {
                        // m3u8 url
                        url = objData.url;
                        document.langs = [];
                        document.baseurl=url.substring(0,url.lastIndexOf('/')+1);
                        m3u8found=true;
                        getpagecontent(m3u8loaded,url);
                    }
                }
            } catch (error) {}
        }
        this.realSend(vData);
    }

    XMLHttpRequest.prototype.send = newSend;

    var buttonhandle = setInterval(function () {
        var buttons = document.getElementsByClassName("control-icon-btn");
        if(buttons.length>0) {
            clickhandle();
        }

        if(oldlocation!=window.location.href&&oldlocation!=null) {
            // location changed
            m3u8found=false;
            document.langs = [];
        }

        oldlocation=window.location.href;
    },100);
};

function m3u8loaded(response) {
    var lines = response.split('#');
    var found = false;
    lines.forEach(function(line) {
        if(line.indexOf('GROUP-ID="sub-main"')>0) {
            // sub infos
            document.langs.push(linetoarray(line));
        }
        else if(line.indexOf('.vtt')>0 && !found) {
            // vtt url
            var url = line.split(',')[1].substring(1);
            found=true;
            getsegment(document.baseurl+"r/"+url,0);
        }
    });
}

function vttloaded(response) {
    if(response.length!="") {
        // save segment
        document.segments+=response.substring(response.indexOf("-->")-13);
        getsegment(vtturl,segid+1);
    }
    else {
        // export segments
        exportfile(vtttosrt(document.segments));
    }
}

function vtttosrt(vtt) {
    var lines = vtt.split(/\r\n|\r|\n/);
    var result = [];
    var subcount = 0;

    lines.forEach(function (line) {
        if(line.indexOf("-->") == 13) {
            subcount++;
            result.push(subcount);
            result.push(line.substring(0,29).replace(/[.]/g,','));
        }
        else if(subcount>0) {
            result.push(line);
        }
    });
    return result.join('\r\n');
}

function linetoarray(line) {
    var result = new Array();
    var values = line.split(',');
    values.forEach(function(value) {
        var data = value.replace('\n','').split('=');
        if(data.length>1) {
            var key = data[0];
            var content = data[1].replace(/"/g,'');
            result[key]=content;
        }
    });
    return result;
}

function clickhandle() {
    var picker = document.getElementsByClassName("options-picker subtitle-track-picker");
    picker[0].childNodes.forEach(function(child) {
        var element = child.childNodes[0];
        var lang = element.childNodes[1].innerHTML;
        if(lang!="Off"&&child.onclick==null) {
        	child.onclick = selectsub;
        }
    });

    filename = document.getElementsByClassName("title-field")[0].innerText;
    if(document.getElementsByClassName("subtitle-field").length>0) {
        episode = document.getElementsByClassName("subtitle-field")[0].innerText
    }
}

function selectsub(e) {
	// Check click position
	if(e.layerX>=345&&e.layerX<=365&&e.layerY>=5&&e.layerY<=25){
		// Download sub
		download(this.childNodes[0].childNodes[1].innerHTML);
		// Cancel selection
		return false;
	}
}

function download(langname) {
    var language;
    var count=0;
    document.forced=false;
    document.langs.forEach(function(lang) {
        if(lang.NAME==langname) {
            language=lang.LANGUAGE;
            document.langid=count;
            getpagecontent(m3u8loaded,document.baseurl+lang.URI);
        }
        count++;
    });
    document.langs.forEach(function(lang) {
        if(lang.LANGUAGE==language && lang.NAME!=langname && lang.FORCED=="YES") {
            document.wait=true;
            document.waitInterval = setInterval(function () {
                if(!document.wait) {
                    document.forced=true;
                    clearInterval(document.waitInterval);
                    getpagecontent(m3u8loaded,document.baseurl+lang.URI);
                }
            },100);
        }
    });
    if(count==0){
        alert("An error has occurred, please reload the page.");
    }
}

function getsegment(url,seg) {
    if(seg==0) {
        document.segments="";
    }
    segid = seg;
    vtturl = url;
    getpagecontent(vttloaded,vtturl.substring(0,vtturl.length-10)+segid.toString().lpad("0", 5)+".vtt");
}

function exportfile(text) {
    var output = filename;
    if(episode!="") {
        output+= " - "+episode.replace(':','');
    }
    output += "."+document.langs[document.langid].LANGUAGE;
    if(document.forced) {
        output += ".forced";
    }
    output += ".srt";

    var hiddenElement = document.createElement('a');

    hiddenElement.href = 'data:attachment/text,' + encodeURI(text);
    hiddenElement.target = '_blank';
    hiddenElement.download = output;
    hiddenElement.click();

    document.wait = false;
}

function getpagecontent(callback,url) {
    var http=new XMLHttpRequest();
    http.open("GET", url, true);
    http.onloadend = function() {
        if(http.readyState == 4 && http.status == 200) {
            callback(http.responseText);
        }
        else if (http.status === 404) {
            callback("");
        }
    }
    http.send();
}

String.prototype.lpad = function(padString, length) {
    var str = this;
    while (str.length < length) {
        str = padString + str;
    }
    return str;
}