有章PDF下载

下载有章文档

// ==UserScript==
// @name         有章PDF下载
// @namespace    http://tampermonkey.net/
// @version      0.0.4
// @description  下载有章文档
// @author       JoyofFire
// @match        https://www.ilawpress.com/assets/plugin/pdfviewer/web/viewer.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ilawpress.com
// @grant        none
// @run-at       document-start
// @license      GPL-3.0-only
// ==/UserScript==


(function() {
    'use strict';


    // 全局常量
    const DL_PDF_API = "download_pdf";
    const DL_BTN = `<button id="dl-pdf" class="extend-navbar-btn fa fa-download" title="下载PDF" style="margin-right:1.1em;color:red" onclick="${DL_PDF_API}()"><span>下载PDF</span></button>`; //`<button id="dl-pdf" class="extend-navbar-btn fa fa-download" title="下载PDF" style="position:fixed;right: 2em;color:red" onclick="${DL_PDF_API}()"><span>下载PDF</span></button>`
    const make_blob_url = get_fn_call(URL, "createObjectURL");
    const insert_html_elem = get_fn_call(Element.prototype, "insertAdjacentHTML");

    function print(...args) {
        const time = new Date().toTimeString().slice(0, 8);
        console.info(`[wk ${time}]`, ...args);
    }

    function get_fn_call(obj, fn_name) {
        const fn = obj[fn_name];
        const call = fn.call.bind(fn);
        print(`got bound ${fn_name}.call:`, call);
        return call;
    }

    /**
     * @param {string} selectors
     * @returns {HTMLElement}
     */
    function $(selectors) {
        return document.querySelector(selectors);
    }


    function add_dl_btn() {
        insert_html_elem($("#toolbarViewerRight"), "afterbegin", DL_BTN);
        print("btn added");
    }

    function on_data(data) {
        const blob = new Blob([data], { type: "application/pdf" });
        const url = make_blob_url(URL, blob);
        
        window.data = data;
        window.url = url;
        window[DL_PDF_API] = () => open(url);

        print("data:", data);
        print("url:", window.url);
    }

    function hook_then() {
        print("entered hook_then");

        const { then } = Promise.prototype;
        Promise.prototype.then = function(...args) {
            for (const [i, arg] of args.entries()) {
                if (String(arg).includes("(pdfDocument) {")) {
                    print(...args);

                    args[i] = function(doc) {
                        print("doc:", doc);
                        doc.getData().then(on_data);
                        return arg.call(this, doc);
                    };
                    break;
                }
            }
            return then.apply(this, args);
        };
    }

    function on_dom_loaded() {
        print("dom loaded");
        add_dl_btn();
    }

    function hook_fetch() {
        const myfetch = get_fn_call(window, "fetch");

        window.fetch = function(url, ...args) {
            //debugger;
            const aim = /[/]pdf[/]trybook[/][0-9]+/;
            const _url = `${url}`;
            const replaced = aim.test(_url)
                ? _url.replace("/trybook/", "/book/")
                : url;
            //debugger;
            const ret_val = myfetch(this, replaced, ...args);
            return ret_val;

            //return myfetch(this, url, ...args);
        };
        print("fetch hooked:", window.fetch);
    }

    function main() {
        print("entered main");

        document.addEventListener("DOMContentLoaded", on_dom_loaded);
        hook_fetch();
        hook_then();
    }

    main();
})();