ApabiDownloader

将最高清晰度的图片打包为PDF

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         ApabiDownloader
// @namespace    https://qinlili.bid/
// @version      0.7
// @description  将最高清晰度的图片打包为PDF
// @author       琴梨梨
// @match        *://*/OnLineReader/Default.aspx?*
// @match        *://cebxol.apabi.com/*
// @match        *://cebxol.apabiedu.com/?metaid=*
// @icon        data:image/x-icon;base64,AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAABEkswAlNb8AJTS/AAEAxwADxckAHrB7ACEsMQAYIWcAH/A5AAiMEwAiM/0ADxQdAAaMEQAGihEAEya3ABsv+wAmeH8AITK9AAJEBwAUarsAERuhACc2fwAPny0ACo6QgBDXmkApeH8AKfg9AAkMDwAMFl0AEeGtABOmMwALD1cAHXB9AARG0QAQFh0AJLI3AAoUIQArun8AKTo/AAyRVwAnNr0AHvH9ACS1/QAHjFcAAQFNAAvPkwAf6m8AERkbABvl6wABAIkAA8YLACc5vwABwo1AAcKIQBMp+QABAMUAAsRLAA2SGwAbLr0AGS47AAEAiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDwzMR8lPDw8PDw8PDw8Lzw8JjwGIzw8MTw8PDw8PBAzMSU3JRgxJSg8PDw8PDw8JiYaLiU1JSI8PDw8PDAzGzElLSUHJQ08FCk8PDw8CyUlJQksPBUqCikhPDw8PDwxFxIxPDw8AzE8PCw8PAwlJSUlGzw8CikFOjc8PDwrOTwxJTUBCCkEPBYTPDw8PDwnGSICHCk4OzI8PDw8PDwsGTQ8ETEPHDQ2ADw8PDw8PDw8PCA8HR48PDw8PDw8PDw8PDw6PCQOPDw8PDw8PDw8PDw8PDw8PDw8PDw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
// @grant        none
// @run-at document-idle
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jspdf.umd.min.js
// ==/UserScript==

(function() {
    'use strict';
    //TODO:页面过多时自动重新划分




    //公共库SakiProgress
    var SakiProgress = {
        isLoaded: false,
        progres: false,
        pgDiv: false,
        textSpan: false,
        first: false,
        alertMode: false,
        init: function (color) {
            if (!this.isLoaded) {
                this.isLoaded = true;
                console.info("SakiProgress Initializing!\nVersion:1.0.3\nQinlili Tech:Github@qinlili23333");
                this.pgDiv = document.createElement("div");
                this.pgDiv.id = "pgdiv";
                this.pgDiv.style = "z-index:9999;position:fixed;background-color:white;min-height:32px;width:auto;height:32px;left:0px;right:0px;top:0px;box-shadow:0px 2px 2px 1px rgba(0, 0, 0, 0.5);transition:opacity 0.5s;display:none;";
                this.pgDiv.style.opacity = 0;
                this.first = document.body.firstElementChild;
                document.body.insertBefore(this.pgDiv, this.first);
                this.first.style.transition = "margin-top 0.5s"
                this.progress = document.createElement("div");
                this.progress.id = "dlprogress"
                this.progress.style = "position: absolute;top: 0;bottom: 0;left: 0;background-color: #F17C67;z-index: -1;width:0%;transition: width 0.25s ease-in-out,opacity 0.25s,background-color 1s;"
                if (color) {
                    this.setColor(color);
                }
                this.pgDiv.appendChild(this.progress);
                this.textSpan = document.createElement("span");
                this.textSpan.style = "padding-left:4px;font-size:24px;";
                this.textSpan.style.display = "inline-block"
                this.pgDiv.appendChild(this.textSpan);
                var css = ".barBtn:hover{ background-color: #cccccc }.barBtn:active{ background-color: #999999 }";
                var style = document.createElement('style');
                if (style.styleSheet) {
                    style.styleSheet.cssText = css;
                } else {
                    style.appendChild(document.createTextNode(css));
                }
                document.getElementsByTagName('head')[0].appendChild(style);
                console.info("SakiProgress Initialized!");
            } else {
                console.error("Multi Instance Error-SakiProgress Already Loaded!");
            }
        },
        destroy: function () {
            if (this.pgDiv) {
                document.body.removeChild(this.pgDiv);
                this.isLoaded = false;
                this.progres = false;
                this.pgDiv = false;
                this.textSpan = false;
                this.first = false;
                console.info("SakiProgress Destroyed!You Can Reload Later!");
            }
        },
        setPercent: function (percent) {
            if (this.progress) {
                this.progress.style.width = percent + "%";
            } else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        clearProgress: function () {
            if (this.progress) {
                this.progress.style.opacity = 0;
                setTimeout(function () { SakiProgress.progress.style.width = "0%"; }, 500);
                setTimeout(function () { SakiProgress.progress.style.opacity = 1; }, 750);
            } else {
                console.error("Not Initialized Error-Please Call `init` First!")
            }
        },
        hideDiv: function () {
            if (this.pgDiv) {
                if (this.alertMode) {
                    setTimeout(function () {
                        SakiProgress.pgDiv.style.opacity = 0;
                        SakiProgress.first.style.marginTop = "";
                        setTimeout(function () {
                            SakiProgress.pgDiv.style.display = "none";
                        }, 500);
                    }, 3000);
                } else {
                    this.pgDiv.style.opacity = 0;
                    this.first.style.marginTop = "";
                    setTimeout(function () {
                        SakiProgress.pgDiv.style.display = "none";
                    }, 500);
                }
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        showDiv: function () {
            if (this.pgDiv) {
                this.pgDiv.style.display = "";
                setTimeout(function () { SakiProgress.pgDiv.style.opacity = 1; }, 10);
                this.first.style.marginTop = (this.pgDiv.clientHeight + 8) + "px";
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        setText: function (text) {
            if (this.textSpan) {
                if (this.alertMode) {
                    setTimeout(function () {
                        if (!SakiProgress.alertMode) {
                            SakiProgress.textSpan.innerText = text;
                        }
                    }, 3000);
                } else {
                    this.textSpan.innerText = text;
                }
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        setTextAlert: function (text) {
            if (this.textSpan) {
                this.textSpan.innerText = text;
                this.alertMode = true;
                setTimeout(function () { this.alertMode = false; }, 3000);
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        setColor: function (color) {
            if (this.progress) {
                this.progress.style.backgroundColor = color;
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        addBtn: function (img) {
            if (this.pgDiv) {
                var btn = document.createElement("img");
                btn.style = "display: inline-block;right:0px;float:right;height:32px;width:32px;transition:background-color 0.2s;"
                btn.className = "barBtn"
                btn.src = img;
                this.pgDiv.appendChild(btn);
                return btn;
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        },
        removeBtn: function (btn) {
            if (this.pgDiv) {
                if (btn) {
                    this.pgDiv.removeChild(btn);
                }
            }
            else {
                console.error("Not Initialized Error-Please Call `init` First!");
            }
        }
    }
    SakiProgress.init();
    console.log("Initializing Apabi Downloader...Engine:AvA PDF");
    var jsPDF=jspdf.jsPDF;
    try{
        console.log(jsPDF)
        console.log("jsPDF Ready!")
    }catch{
        console.error("jsPDF Not Ready!")
    }
    //解除右键
    document.body.oncontextmenu = ""
    var pageTotal = 0;
    var picUrl = ""
    var pageCurrent = 1;
    var donePage=0;
    var urlhost = "";
    var PDFfile=false;
    var imgList=[];
    var imgDataList=[];
    var imgEle=document.createElement("img");
    document.body.appendChild(imgEle);






    //Array多线程快速下载
    function downloadPicList(list,dataList) {
        for(var j=0;list[j];j++){
            toDataURL(list[j],j,function(data,page){
                dataList[page]=data;
                donePage++
                SakiProgress.setPercent(donePage/pageTotal*90)
                SakiProgress.setText("已下载"+donePage+"页...")
                if(donePage==pageTotal){
                    SakiProgress.setText("准备生成PDF...")
                    makePDF();
                }
            })
        }




        //读取图片
        function toDataURL(url,page, callback) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange=()=>{
                if(xhr.readyState === 4 && xhr.status >300) {
                    console.log("错误,重试:"+url)
                    toDataURL(url,page,callback);
                }
            }
            xhr.onload = function() {
                var reader = new FileReader();
                reader.onloadend = function() {
                    callback(reader.result,page);
                }
                reader.readAsDataURL(xhr.response);
            };
            xhr.open('GET', url);
            xhr.responseType = 'blob';
            xhr.send();
        }
    }



    //制作PDF
    function makePDF(){
        for(var k=0;imgDataList[k];k++){
            imgEle.src=imgDataList[k];
            PDFfile.addImage(imgDataList[k],"JPEG",0,0,imgEle.naturalWidth,imgEle.naturalHeight,"Page"+(k+1),"SLOW")
            PDFfile.addPage();
            SakiProgress.setText("已生成"+k+"页...")
        }
        SakiProgress.setText("正在制作PDF...")
        PDFfile.save("Apabi.pdf",{returnPromise:true}).then(finish => {
            SakiProgress.clearProgress;
            SakiProgress.hideDiv();
        });
    }
    //批量下载
    function batchDownload() {
        SakiProgress.showDiv()
        SakiProgress.setText("正在读取页面信息...")
        //最大化图片尺寸
        currentHeight = 4096;
        currentWidth = 4096;
        pageTotal = document.getElementById("TotalCount").innerText;
        console.log("Initializing image list...")
        if (document.location.host=="cebxol.apabi.com"||document.location.host=="cebxol.apabiedu.com"){
            urlhost="/"
        }else{
            urlhost="/OnLineReader/"
        }
        for(var i=1;i<=pageTotal;i++){
            imgList[i-1]=window.location.origin + urlhost + encodeURI(getUrl(i));
        }
        SakiProgress.setText("正在读取参数并建立PDF...")
        imgEle.onload=function(){
            var ori
            if(imgEle.naturalWidth>imgEle.naturalHeight){ori="l"}else{ori="p"}
            PDFfile=new jsPDF({
                orientation: ori,
                unit: 'px',
                format: [imgEle.naturalWidth,imgEle.naturalHeight],
                putOnlyUsedFonts:true,
            });
            SakiProgress.setText("正在准备下载页面...")
            downloadPicList(imgList,imgDataList)
        }
        imgEle.src=imgList[0]
    }

    //导出目录
    function indexDownload(){
    }

    //创建下载按钮
    document.querySelector("body > div.page > div.header").style.width="auto"
    var downloadBtn = document.createElement("a");
    downloadBtn.innerText = "下载全书";
    downloadBtn.onclick = function () { batchDownload() }
    document.querySelector("body > div.page > div.header > ul").appendChild(downloadBtn);
    var downloadIndexBtn = document.createElement("a");
    downloadIndexBtn.innerText = "下载目录";
    downloadIndexBtn.onclick = function () { indexDownload() }
    document.querySelector("body > div.page > div.header > ul").appendChild(downloadIndexBtn);

})();