Disney+ Subtitles Downloader

Download subtitles from Disney+

当前为 2020-08-18 提交的版本,查看 最新版本

// ==UserScript==
// @name           Disney+ Subtitles Downloader
// @name:fr        Disney+ Subtitles Downloader
// @namespace      https://gf.qytechs.cn/fr/users/572942-stegner
// @homepage       https://gf.qytechs.cn/fr/scripts/404223-disney-subtitles-downloader
// @description    Download subtitles from Disney+
// @description:fr Télécharger les sous-titres de Disney+
// @version        2.2
// @author         stegner
// @match          https://www.disneyplus.com/*
// @grant          none
// @require        https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// @require        https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js
// @run-at         document-start
// ==/UserScript==

(function() {
    'use strict';
    var debug = (location.hash=="#debug") ? true : false;
    debuglog("Script loaded : Disney+ Subtitles Downloader");

    function init(){
        debuglog("Document state : "+document.readyState);
        if (document.readyState == "complete" || document.readyState == "loaded"){
            start();
            debuglog("Already loaded");
        }
        else {
            if (window.addEventListener) {
                window.addEventListener("load", start, false);
                debuglog("Onload method : addEventListener");
            } else if (window.attachEvent) {
                window.attachEvent("onload", start);
                debuglog("Onload method : attachEvent");
            } else {
                window.onload = start;
                debuglog("Onload method : onload");
            }
        }
        document.listen=true;
    }

    function start(){
        if(!document.started){
            debuglog("start");
            document.started=true;
            if (typeof document.initaudio !== "undefined") {
                document.initaudio();
            }
            if (typeof document.initsub !== "undefined") {
                document.initsub();
            }
            listensend();
            document.handleinterval = setInterval(buttonhandle,100);
        }
    }

    if(!document.listen){
        init();
    }

    document.initsub = function(){
        debuglog("initsub");
        document.langs = new Array();
        document.segments = "";
        document.forced=false;
        document.wait=false;
        document.m3u8found=false;
        document.url=null;
        document.oldlocation=null;
        document.filename="";
        document.episode="";
        document.downloadall=false;
        document.downloadid=0;
        document.waitsub=false;
        var segid=0;
        var vtturl;

        // Add download icon
        document.styleSheets[0].addRule('#subtitleTrackPicker > div:before','content:"";color:#fff;padding-right:25px;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:20px;position:absolute;top:6px;right:10px;opacity:0.6;cursor:pointer;');
        document.styleSheets[0].addRule('#subtitleTrackPicker > div:hover:before','opacity:1;');
        document.styleSheets[0].addRule('#subtitleTrackPicker > div:first-child:before','content:"All";');
    };

    // Catch M3U8 files
    function listensend(){
        debuglog("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.m3u8sub = function(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 && line.indexOf('BUMPER')<0) {
                // vtt url
                var uri = document.langs[document.langid].URI;
                var url = line.split(',')[1].substring(1);
                found=true;
                if(url.indexOf("/")<0){
                    url = uri.substring(2,uri.lastIndexOf("/")+1) + url;
                }
                getsegment(document.baseurl+uri.substring(0,2)+url,0);
            }
        });
    }

    function vttloaded(response) {
        if(response.length>0) {
            // save segment
            document.segments+=response.substring(response.indexOf("-->")-13);
            getsegment(vtturl,segid+1);
        }
        else if(document.segments.length>0) {
            // export segments
            exportfile(vtttosrt(document.segments));
        }
        else {
            alert("Unknown error, please report a bug for this video.");
        }
    }

    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.replace(/<\/?c(\.\w{1,})?>/g,'').replace(/&amp;/g,'&'));
            }
        });
        return result.join('\r\n');
    }

    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.langs = [];
            document.audios = [];
        }

        document.oldlocation=window.location.href;
    }

    document.clickhandlesub = function() {
        var picker = document.getElementsByClassName("options-picker subtitle-track-picker");
        picker[0].childNodes.forEach(function(child) {
            var element = child.childNodes[0];
            if(child.onclick==null) {
                child.onclick = selectsub;
            }
        });
    }

    function selectsub(e) {
        var width = this.offsetWidth;
        // Check click position
        if(e.layerX>=width-30&&e.layerX<=width-10&&e.layerY>=5&&e.layerY<=25){
        	var lang = this.childNodes[0].childNodes[1].innerHTML;
        	if(lang=="Off"){
        		// Download all subs
        		document.zip = new JSZip();
        		document.downloadall=true;
        		document.downloadid=-1;
        		downloadnext();
        	}
        	else {
            	// Download sub
            	download(lang);
            }
            // Cancel selection
            return false;
        }
    }

    function downloadnext(){
    	document.downloadid++;
    	while(typeof document.langs[document.downloadid] !== 'undefined' && document.langs[document.downloadid].FORCED=="YES"){
    		document.downloadid++;
    	}

    	if(document.downloadid<document.langs.length){
        	document.styleSheets[0].addRule('#subtitleTrackPicker > div:first-child:before','padding-right:35px;content:"'+Math.round((document.downloadid/document.langs.length)*100)+'%";');
    		download(document.langs[document.downloadid].NAME);
    	}
    	else {
    		clearInterval(document.downloadinterval);
        	document.styleSheets[0].addRule('#subtitleTrackPicker > div:first-child:before','padding-right:25px;content:"All";');

    		document.zip.generateAsync({type:"blob"}).then(function(content) {
    			var output = document.filename;
    			if(document.episode!="") {
    				output+= " - "+document.episode.replace(':','');
    			}
    			saveAs(content, output+".zip");
    		});
    	}
    }

    function download(langname) {
        if(!document.wait){
            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);
                    document.wait=true;
                }
                count++;
            });
            document.langs.forEach(function(lang) {
                if(lang.LANGUAGE==language && lang.NAME!=langname && lang.FORCED=="YES") {
        			document.waitsub=true;
                    document.waitInterval = setInterval(function () {
                        if(!document.wait) {
                            document.forced=true;
                            clearInterval(document.waitInterval);
                            getpagecontent(m3u8loaded,document.baseurl+lang.URI);
                            document.wait=true;
                        }
                    },10);
                }
            });
            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 = document.filename;
        if(document.episode!="") {
            output+= " - "+document.episode.replace(':','');
        }
        output += "."+document.langs[document.langid].LANGUAGE;
        if(document.forced) {
            output += ".forced";
            document.waitsub=false;
        }
        output += ".srt";

        if(document.downloadall){
       		document.zip.file(output, text);
        	document.downloadinterval = setTimeout(function () { 
        		document.wait = false;
        		if(!document.waitsub){
        			downloadnext();
        		}
        	},20);
        }
        else {
    	    var hiddenElement = document.createElement('a');

    	    hiddenElement.href = 'data:attachment/text,' + encodeURI(text);
    	    hiddenElement.target = '_blank';
    	    hiddenElement.download = output;
    	    hiddenElement.click();
        	setTimeout(function () { document.wait = false; },50);
        }
    }

    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;
    }

    function debuglog(message){
        if(debug){
            console.log("%c [debug] "+message, 'background: #222; color: #bada55');
        }
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址