Greasy Fork is available in English.

文库下载器,VIP文档免费下载 | 全文阅读| 开启右键复制

【本脚本功能】保持源文件排版导出 PDF 文件,解除继续阅读限制,净化弹窗、广告,开启文库本地 VIP,淘宝、天猫、京东商品优惠券查询

As of 26.08.2022. See ბოლო ვერსია.

// ==UserScript==
// @name         文库下载器,VIP文档免费下载 | 全文阅读| 开启右键复制
// @version      1.6.3
// @description  【本脚本功能】保持源文件排版导出 PDF 文件,解除继续阅读限制,净化弹窗、广告,开启文库本地 VIP,淘宝、天猫、京东商品优惠券查询
// @author       zhihu
// @antifeature  membership  为防止接口被盗!该脚本需要输入验证码之后才能使用完整功能,感谢理解
// @antifeature  referral-link 【此提示为GreasyFork代码规范要求含有查券功能的脚本必须添加,实际使用无任何强制跳转,代码可查,请知悉】
// @license      End-User License Agreement
// @match        *://wenku.baidu.com/view*
// @match        *://wk.baidu.com/view*
// @match        *://wenku.baidu.com/tfview*
// @match        *://wk.baidu.com/tfview*
// @match        *://item.taobao.com/*
// @match        *://chaoshi.detail.tmall.com/*
// @match        *://*detail.tmall.com/*
// @match        *://*detail.tmall.hk/*
// @match        *://*item.jd.com/*
// @match        *://npcitem.jd.hk/*
// @match        *://*.yiyaojd.com/*
// @icon         https://www.baidu.com/favicon.ico
// @grant        GM_getValue
// @grant        GM.getValue
// @grant        GM_setValue
// @grant        GM.setValue
// @connect      bdimg.com
// @connect      tool.wezhicms.com
// @connect      zhihuweb.com
// @grant        unsafeWindow
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @run-at       document-start
// @namespace    http://zhihupe.com/
// ==/UserScript==

(function() {
    'use strict';
    var qrname,nodeid,goodid,method,action,updateconfig;
    const scpritversion = "1.6.1";
    function Toast(msg, duration = 3000) {
        var m = document.createElement('div');
        m.innerHTML = msg;
        m.style.cssText = "max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
        document.body.appendChild(m);
        setTimeout(() => {
            var d = 0.5;
            m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
            m.style.opacity = '0';
            document.body.removeChild(m)
        }, duration);
    }
    function Getgoodid(gid) {
        var reg = new RegExp("(^|&)" + gid + "=([^&]*)(&|$)");
        var s = window.location.search.substr(1).match(reg);
        if (s != null) {
            return s[2];
        }
        return "";
    }
    function geturlid(url) {
        if (url.indexOf("?") != -1) {
            url = url.split("?")[0]
        }
        if (url.indexOf("#") != -1) {
            url = url.split("#")[0]
        }
        var text = url.split("/");
        var id = text[text.length - 1];
        id = id.replace(".html", "");
        return id
    }
    function Commonsetinterval(data){
            var Count;
            var num ="";
            return new Promise(function(resolve, reject){
                Count = setInterval(function() {
                  data.forEach((item,index)=>{
                    var node = document.querySelector(item);
                    if(node != null ){
                        resolve(node);
                        clearInterval(Count);
                    }
                    if(num ==100){
                        clearInterval(Count);
                    }
                    num++;
                  });
                },200);
            });
        }
    function Getcoupon(t) {
        if (t != "") {
            GM_xmlhttpRequest({
                method: "GET",
                url: "http://tool.wezhicms.com/coupon/getcoupon.php?m=" + method + "&act=" + action + "&goodid=" + t,
                headers: {
                    "Content-Type": "text/html; charset=utf-8"
                },
                onload: function(res) {
                    var json = JSON.parse(res.responseText);
                    var code = json.code;
                    console.log(json);
                    if (method == "taobao") {
                        if (code == "0") {
                            var longTpwd = json.data.longTpwd
                            var couponUrl = longTpwd.match(/https:\/\/[\d\w\.\/]+/)[0];
                            console.log(longTpwd);
                            console.log(couponUrl);
                            var couponInfo = json.data.couponInfo;
                            var couponEndTime = json.data.couponEndTime;
                            var actualPrice = json.data.actualPrice;
                            addcoupon(couponUrl, couponInfo, couponEndTime, actualPrice,t)
                        }else{
                            let u="",f="",t="",p="";
                            addcoupon(u, f, t, p);
                        }
                    } else if (method == "jd") {
                        if (code == "0") {
                            var couponConditions = json.data[0].couponConditions;
                            var couponAmount = json.data[0].couponAmount;
                            var jdcouponInfo;
                            if (couponConditions != "") {
                                jdcouponInfo = "满" + couponConditions + "元减" + couponAmount + "元"
                            } else {
                                jdcouponInfo = "无门槛减" + couponAmount + "元"
                            }
                            var jdcouponEndTime = json.data[0].couponEndTime
                            var jdactualPrice = json.data[0].actualPrice;
                            var couponLink = json.data[0].couponLink;
                            addcoupon(couponLink, jdcouponInfo, jdcouponEndTime, jdactualPrice,"")
                        }else{
                            let u="",f="",t="",p="";
                            addcoupon(u, f, t, p);
                        }
                    }
                },
                onerror: function(err) {
                    console.log(err);
                }
            });
        } else {
            console.log('商品id为空!');
        }
    }
    function addcoupon(u, f, t, p,goodid) {
        var imgurl = "http://v.zhihupe.com/enQrcode?url=" + u
        var mainhtml,qa,cxalink,link;
        if(qrname =="淘宝"){
            let ht = document.querySelector("#J_Title");
            link ="http://tool.wezhicms.com/coupon/getscan.php?link="+u+"&goodid="+goodid
            qa = "淘宝";
            cxalink ='http://wxego.yhzu.cn/?r=/l&kw='+encodeURI(ht.querySelector("h3").innerText)+'&sort=0';
        }else if(qrname =="天猫"){
            let hm = document.querySelector(".tb-detail-hd")??document.querySelector(".ItemHeader--root--DXhqHxP");
            link ="http://tool.wezhicms.com/coupon/getscan.php?link="+u+"&goodid="+goodid
            cxalink ='http://wxego.yhzu.cn/?r=/l&kw='+encodeURI(hm.querySelector("h1").innerText)+'&sort=0';
            qa = "淘宝";
        }else if(qrname =="京东"){
            cxalink = 'http://wxego.yhzu.cn/?r=/l/jdlist&kw='+encodeURI(document.querySelector(".sku-name").innerText)+'&sort=0';
            link =u
            qa = "京东";
        }

        if (f != "" && u != "") {
            mainhtml = '<div style="text-align: center;font-size: 14px;width: 25%;"><img style="width: 100%;height: auto;"src="' + imgurl + '"><p style="font-size: 12px;margin-top: 5px;">手机' + qa + '扫码领取</p></div><div style="width: 72%;"><p style="margin-bottom:10px;font-size: 18px;font-weight: 700;">优惠劵:' + f + '</p><p style="margin-bottom:10px;font-size: 14px;color:#999;">有效期至:' + t + '</p><div style="display: flex;justify-content: space-between;align-items: flex-start;"><div><span style="font-size:14px">劵后价:</span><span style="font-size: 18px;font-weight: 700;color: #F40;">¥</span><span style="font-size: 26px;font-weight: 700;font-family: Tahoma,Arial,Helvetica,sans-serif;color: #F40;">' + p + '</span></div><a id="link"><span style="padding: 10px 20px;background-color: #df3033;font-size: 18px;color: #fff;font-weight: 700;">领券购买</span></a></div></div>'
        } else {
            mainhtml = '<div style="font-size: 18px;font-weight: 700;">暂无优惠券</div><a id="cxalink" style="background: #df3033;padding: 10px;color: #fff;font-size: 12px;">查询同款商品优惠</a>'
        }
        var couponhtml = '<div id="wenkucoupon" style="margin-top: 10px;background: #f1f1f100;padding: 15px 25px 15px 0;display:flex;align-items: center;justify-content: space-between;margin-bottom:5px;font-family: tahoma,arial,Microsoft YaHei,Hiragino Sans GB;">' + mainhtml + '</div>';
        let AddBiPromise = Commonsetinterval(nodeid)
        AddBiPromise.then(function(c){
            let b = document.createElement('div');
            b.style="min-width:460px"
            b.innerHTML = couponhtml;
            if(unsafeWindow?.zhihu == true) return;
            c.parentNode.appendChild(b);
            unsafeWindow.zhihu = true;
            let linknode = document.querySelector("#link");
            if(linknode){
                linknode.onclick = function() {
                    window.open(link);
                };
            }
            let cxalinknode = document.querySelector("#cxalink");
            if(cxalinknode){
                cxalinknode.onclick = function() {
                    window.open(cxalink);
                };
            }
        });
    }
    var Wenku = {
        open:function(data){
            var main = document.createElement('div');
            var width = data.area[0];
            var height = data.area[1];
            var margintop = height/2;
            var marginleft = width/2;
            var style = "z-index: 999999998;width: "+width+"px;height:"+height+"px;position: fixed;top: 50%;left: 50%;margin-left:-"+marginleft+"px;margin-top:-"+margintop+"px;"
            var btnHTML = '<a class="zhihu-layer-btn0">'+data.btn[0]+'</a><a class="zhihu-layer-btn1">'+data.btn[1]+'</a>';
            main.innerHTML = '<div class="zhihu-layer-title" style="cursor: move;">'+data.title+'</div><div class="zhihu-layer-content" >'+data.content+'</div><span class="zhihu-layer-setwin"><a class="zhihu-layer-ico zhihu-layer-close1" href="javascript:;"></a></span><div class="zhihu-layer-btn zhihu-layer-btn-c">'+btnHTML+'</div>';
            main.setAttribute('id',data.id);
            main.setAttribute('style',style);
            main.setAttribute('class',"zhihu-layer-page");
            document.body.appendChild(main);
            var shade = document.createElement('div');
            shade.setAttribute('style',"z-index: 999999997;background-color: rgb(0, 0, 0);opacity: 0.3;");
            shade.setAttribute('class',"zhihu-layer-shade");
            shade.setAttribute('id',"zhihu-layer-shade");
            shade.innerHTML =''
            document.body.appendChild(shade);
            var css = `
             ::-webkit-scrollbar {
                height: 6px;
                width: 6px;
             }
             ::-webkit-scrollbar-track {
                background: transparent;
                width: 6px;
             }
             ::-webkit-scrollbar-thumb {
                background-color: #54be99;
                border-radius: 4px;
                -webkit-transition: all 1s;
                transition: all 1s;
                width: 6px;
             }
             ::-webkit-scrollbar-corner {
                background-color: #54be99;
             }
             li {
               list-style: none;
             }
             .zhihu-form-label, .zhihu-form-select, .zhihu-input-block, .zhihu-input-inline{
               position: relative;
             }
             .zhihu-layer-shade {
               top: 0;
               left: 0;
               width: 100%;
               height: 100%;
               position: fixed;
               _height: expression(document.body.offsetHeight+"px");
             }
             .zhihu-layer-page{
                   margin: 0;
                   padding: 0;
                   background-color: #fff;
                   border-radius: 10px;
                   box-shadow: 1px 1px 50px rgba(0,0,0,.4);
                   font-family: PingFang SC, HarmonyOS_Regular, Helvetica Neue, Microsoft YaHei, sans-serif;
             }
             .zhihu-layer-title{
                   padding: 0 80px 0 20px;
                   height: 50px;
                   line-height: 50px;
                   border-bottom: 1px solid #F0F0F0;
                   border-radius: 2px 2px 0 0;
                   font-size: 14px;
                   color: #333;
                   overflow: hidden;
                   text-overflow: ellipsis;
                   white-space: nowrap;
                   font-weight: bold;
             }
             .zhihu-layer-setwin {
                   position: absolute;
                   right: 15px;
                   top: 17px;
                   font-size: 0;
                   line-height: initial;
              }
              .zhihu-layer-setwin .zhihu-layer-close1 {
                   background-position: 1px -40px;
                   cursor: pointer;
              }
              .zhihu-layer-setwin a {
                   position: relative;
                   width: 16px;
                   height: 16px;
                   margin-left: 10px;
                   font-size: 12px;
                   _overflow: hidden;
              }
             .zhihu-layer-btn a, .zhihu-layer-setwin a {
                   display: inline-block;
                   vertical-align: top;
              }
              .zhihu-layer-ico {
                   background: url(https://www.layuicdn.com/layui/css/modules/layer/default/icon.png) no-repeat;
              }
              .zhihu-layer-btn {
                   text-align: right;
                   padding: 10px 15px 12px;
                   pointer-events: auto;
                   user-select: none;
                   -webkit-user-select: none;
              }
              .zhihu-layer-btn-c {
                   text-align: center;
              }
              .zhihu-layer-btn a {
                   height: 28px;
                   line-height: 28px;
                   margin: 5px 5px 0;
                   padding: 0 15px;
                   border: 1px solid #dedede;
                   background-color: #fff;
                   color: #333;
                   border-radius: 4px;
                   font-weight: 400;
                   cursor: pointer;
                   text-decoration: none;
               }
               .zhihu-layer-btn1 {
                   border-color: #54be99!important;
                   background-color: #54be99!important;
                   color: #fff!important;
               }
               .zhihu-form-item {
                   margin-bottom: 5px;
                   clear: both;
               }
               .zhihu-form-label {
                   float: left;
                   display: block;
                   padding: 9px 15px;
                   width: 80px;
                   font-weight: 400;
                   line-height: 20px;
                   text-align: right;
                   box-sizing: content-box;
                }
                .zhihu-input-inline {
                   display: inline-block;
                   vertical-align: middle;
                   width: 190px;
                   margin-right: 10px;
                }
                .zhihu-input, .zhihu-select, .zhihu-textarea {
                   height: 38px;
                   line-height: 1.3;
                   border-width: 1px;
                   border-style: solid;
                   border-color: #eee;
                   display: block;
                   width: 100%;
                   padding-left: 10px;
                   background-color: #fff;
                   color: rgba(0,0,0,.85);
                   border-radius: 2px;
                   outline: 0;
                   -webkit-appearance: none;
                   transition: all .3s;
                   -webkit-transition: all .3s;
                   box-sizing: border-box;
                }
                .zhihu-input-block {
                   min-height: auto;
                   margin-left: 110px;
                }
                .zhihu-input-block p {
                   font-size: 12px;
                   line-height: 22px;
                }
                .zhihu-form {
                   display: flex;
                   margin-top: 20px;
                }

            `;
            Wenku.GMaddStyle(css,"open");
            // await commonFunction.sleep(1000);
            //获取表单对象
            var zhihuform = document.querySelector('.zhihu-form');
            //保存按钮点击事件
            document.querySelector('.zhihu-layer-btn1').addEventListener('click',function() {
                data.btn1(zhihuform);
                document.body.removeChild(document.querySelector(".zhihu-layer-page"));
                document.body.removeChild(document.querySelector("#zhihu-layer-shade"));
                document.getElementsByTagName("head").item(0).removeChild(document.getElementById("open"));
            })
            //取消钮点击事件
            document.querySelector(".zhihu-layer-btn0").addEventListener('click',function() {
                document.body.removeChild(document.querySelector(".zhihu-layer-page"));
                document.body.removeChild(document.querySelector("#zhihu-layer-shade"));
                document.getElementsByTagName("head").item(0).removeChild(document.getElementById("open"));
            })
            //关闭钮点击事件
            document.querySelector(".zhihu-layer-close1").addEventListener('click',function() {
                document.body.removeChild(document.querySelector(".zhihu-layer-page"));
                document.body.removeChild(document.querySelector("#zhihu-layer-shade"));
                document.getElementsByTagName("head").item(0).removeChild(document.getElementById("open"));
            })
        },
        GMaddStyle:function(data,id=null) {
            var addStyle = document.createElement('style');
            addStyle.textContent = data;
            addStyle.type = 'text/css';
            addStyle.id = id;
            var doc = document.head || document.documentElement;
            doc.appendChild(addStyle);
        },
        GetVip:function(){
            // 注册个 MutationObserver,根治各种垃圾弹窗
            let count = 0;
            const blackListSelector = [
                '.vip-pay-pop-v2-wrap',
                '.reader-pop-manager-view-containter',
                '.fc-ad-contain',
                '.shops-hot',
                '.video-rec-wrap',
                '.pay-doc-marquee',
                '.card-vip',
                '.vip-privilege-card-wrap',
                '.doc-price-voucher-wrap',
                '.vip-activity-wrap-new',
                '.creader-root .hx-warp',
                '.hx-recom-wrapper',
                '.hx-bottom-wrapper',
                '.hx-right-wrapper.sider-edge'
            ]

            const killTarget = (item) => {
                if (item.nodeType !== Node.ELEMENT_NODE) return false;
                let el = item;
                if (blackListSelector.some(i => (item.matches(i) || (el = item.querySelector(i)))))
                    el?.remove(), count++;
                return true
            }
            const observer = new MutationObserver((mutationsList) => {
                for (let mutation of mutationsList) {
                    killTarget(mutation.target)
                    for (const item of mutation.addedNodes) {
                        killTarget(item)
                    }
                }
            });
            observer.observe(document, { childList: true, subtree: true });
            window.addEventListener("load", () => {
                console.log(`[-] 文库净化:共清理掉 ${count} 个弹窗~`);
            });
            let pageData, pureViewPageData;
            Object.defineProperty(unsafeWindow, 'pageData', {
                set: v => pageData = v,
                get() {
                    if (!pageData) return pageData;

                    // 启用 VIP
                    if('vipInfo' in pageData) {
                        pageData.vipInfo.global_svip_status = 1;
                        pageData.vipInfo.global_vip_status = 1;
                        pageData.vipInfo.isVip = 1;
                        pageData.vipInfo.isWenkuVip = 1;
                    }

                    if ('readerInfo' in pageData && pageData?.readerInfo?.htmlUrls?.json) {
                        pageData.readerInfo.showPage = pageData.readerInfo.htmlUrls.json.length;
                    }

                    if ('appUniv' in pageData) {
                        // 取消百度文库对谷歌、搜狗浏览器 referrer 的屏蔽
                        pageData.appUniv.blackBrowser = [];

                        // 隐藏 APP 下载按钮
                        pageData.viewBiz.docInfo.needHideDownload = true;
                    }

                    return pageData
                }
            })
            Object.defineProperty(unsafeWindow, 'pureViewPageData', {
                set: v => pureViewPageData = v,
                get() {
                    if (!pureViewPageData) return pureViewPageData;

                    // 去除水印,允许继续阅读
                    if('customParam' in pureViewPageData) {
                        pureViewPageData.customParam.noWaterMark = 1;
                        pureViewPageData.customParam.visibleFoldPage = 1;
                    }

                    if('readerInfo2019' in pureViewPageData) {
                        pureViewPageData.readerInfo2019.freePage = pureViewPageData.readerInfo2019.page;
                    }

                    return pureViewPageData
                }
            })
        },
        Downdocs:function(){
            // 拿到阅读器的 Vue 实例
            // https://github.com/EHfive/userscripts/tree/master/userscripts/enbale-vue-devtools
            function observeVueRoot(callbackVue) {
                const checkVue2Instance = (target) => {
                    const vue = target && target.__vue__
                    return !!(
                        vue
                        && (typeof vue === 'object')
                        && vue._isVue
                        && (typeof vue.constructor === 'function')
                    )
                }

                const vue2RootSet = new WeakSet();
                const observer = new MutationObserver(
                    (mutations, observer) => {
                        const disconnect = observer.disconnect.bind(observer);
                        for (const { target } of mutations) {
                            if (!target) {
                                return
                            } else if (checkVue2Instance(target)) {
                                const inst = target.__vue__;
                                const root = inst.$parent ? inst.$root : inst;
                                if (vue2RootSet.has(root)) {
                                    // already callback, continue loop
                                    continue
                                }
                                vue2RootSet.add(root);
                                callbackVue(root, disconnect);
                            }
                        }
                    }
                );
                observer.observe(document, {
                    attributes: true,
                    subtree: true,
                    childList: true
                });
                return observer
            }

            const creaderReady = new Promise(resolve => {
                observeVueRoot((el, disconnect) => {
                    while (el.$parent) {
                        // find base Vue
                        el = el.$parent
                    }

                    const findCreader = (root, selector) => {
                        if (!root) return null;
                        if (root?.$el?.nodeType === Node.ELEMENT_NODE && 'creader' in root && 'renderPages' in root.creader) return root.creader;

                        for (const child of root.$children) {
                            let found = findCreader(child, selector);
                            if (found) return found;
                        }
                        return null;
                    }

                    unsafeWindow['__creader__'] = findCreader(el);
                    disconnect();
                    resolve(unsafeWindow['__creader__']);
                   
                });
            });
            ///////////////////////////////////////////////////////////////////////////////////////////////

            const loadScript = url => new Promise((resolve, reject) => {
                const removeWrap = (func, ...args) => {
                    if (script.parentNode) script.parentNode.removeChild(script);
                    return func(...args)
                }

                const script = document.createElement('script');
                script.src = url;
                script.onload = removeWrap.bind(null, resolve);
                script.onerror = removeWrap.bind(null, reject);
                document.head.appendChild(script);
            })

            const loadJsPDF = async () => {
                if (unsafeWindow.jspdf) return unsafeWindow.jspdf;
                await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js');
                return unsafeWindow.jspdf;
            }

            creaderReady.then(async creader => {
                const showStatus = (text='', progress=-1) => {
                    document.querySelector('.s-top.s-top-status').classList.add('show');
                    if(text) document.querySelector('.s-panel .s-text').innerHTML = text;
                    if (progress >= 0) {
                        progress = Math.min(progress, 100);
                        document.querySelector('.s-panel .s-progress').style.width = `${Math.floor(progress)}%`;
                        document.querySelector('.s-panel .s-progress-text').innerHTML = `${Math.floor(progress)}%`;
                    }
                }

                const hideStatus = () => {
                    document.querySelector('.s-top.s-top-status').classList.remove('show');
                }

                let lastMessageTimer;
                const showMessage = (msg, time=3000) => {
                    const msgEl = document.querySelector('.s-top.s-top-message');
                    msgEl.classList.add('show');
                    document.querySelector('.s-top.s-top-message .s-message').innerHTML = msg;
                    clearTimeout(lastMessageTimer);
                    lastMessageTimer = setTimeout(() => msgEl.classList.remove('show'), time);
                }

                const loadImage = (url) => new Promise(async (resolve, reject) => {
                    if (!url) {
                        resolve(null);
                        return;
                    }

                    let img = await request('GET', url, null, 'blob');
                    let imgEl = document.createElement('img');
                    imgEl.onload = () => {
                        resolve(imgEl);
                    }
                    imgEl.onabort = imgEl.onerror = reject;
                    imgEl.src = URL.createObjectURL(img);
                })

                const drawNode = async (doc, page, node) => {
                    if (node.type == 'word') {
                        for (let font of node.fontFamily) {
                            font = /['"]?([^'"]+)['"]?/.exec(font)
                            if (!font || page.customFonts.indexOf(font[1]) === -1) continue;

                            doc.setFont(font[1], node.fontStyle);
                            break;
                        }

                        doc.setTextColor(node.color);
                        doc.setFontSize(node.fontSize);

                        const options = {
                            charSpace: node.letterSpacing,
                            baseline: 'top'
                        };
                        const transform = new doc.Matrix(
                            node.matrix?.a ?? node.scaleX,
                            node.matrix?.b ?? 0,
                            node.matrix?.c ?? 0,
                            node.matrix?.d ?? node.scaleY,
                            node.matrix?.e ?? 0,
                            node.matrix?.f ?? 0);

                        if (node.useCharRender) {
                            for (const char of node.chars)
                                doc.text(char.text, char.rect.left, char.rect.top, options, transform);
                        } else {
                            doc.text(node.content, node.pos.x, node.pos.y, options, transform);
                        }
                    } else if (node.type == 'pic') {
                        let img = page._pureImg;
                        if (!img) {
                            console.debug('[+] page._pureImg is undefined, loading...');
                            img = await loadImage(node.src);
                        }

                        if (!('x1' in node.pos)) {
                            node.pos.x0 = node.pos.x1 = node.pos.x;
                            node.pos.y1 = node.pos.y2 = node.pos.y;
                            node.pos.x2 = node.pos.x3 = node.pos.x + node.pos.w;
                            node.pos.y0 = node.pos.y3 = node.pos.y + node.pos.h;
                        }

                        const canvas = document.createElement('canvas');
                        const [w, h] = [canvas.width, canvas.height] = [node.pos.x2 - node.pos.x1, node.pos.y0 - node.pos.y1];
                        const ctx = canvas.getContext('2d');

                        if (node.pos.opacity && node.pos.opacity !== 1) ctx.globalAlpha = node.pos.opacity;
                        if (node.scaleX && node.scaleX !== 1) ctx.scale(node.scaleX, node.scaleY);
                        if (node.matrix) ctx.transform(node.matrix.a ?? 1, node.matrix.b ?? 0, node.matrix.c ?? 0, node.matrix.d ?? 1, node.matrix.e ?? 0, node.matrix.f ?? 0);

                        ctx.drawImage(img, node.picPos.ix, node.picPos.iy, node.picPos.iw, node.picPos.ih, 0, 0, node.pos.w, node.pos.h);
                        doc.addImage(canvas, 'PNG', node.pos.x1, node.pos.y1, w, h);

                        canvas.remove();
                    }
                }

                const request = (method, url, data, responseType = 'text') => new Promise((resolve, reject) => {
                    GM.xmlHttpRequest({
                        method,
                        url,
                        data,
                        responseType,
                        onerror: reject,
                        ontimeout: reject,
                        onload: (response) => {
                            if (response.status >= 200 && response.status < 300) {
                                resolve(responseType === 'text' ? response.responseText : response.response);
                            } else {
                                reject(new Error(response.statusText));
                            }
                        }
                    });
                });

                const loadFont = async (doc, page) => {
                    const apiBase = 'https://wkretype.bdimg.com/retype';
                    let params = ["pn=" + page.index, "t=ttf", "rn=1", "v=" + page.readerInfo.pageInfo.version].join("&");
                    let ttf = page.readerInfo.ttfs.find(ttf => ttf.pageIndex === page.index)
                    if (!ttf) return;

                    let resp = await request('GET', apiBase + "/pipe/" + page.readerInfo.storeId + "?" + params + ttf.params)
                    if (!resp) return;
                    resp = resp.replace(/[\n\r ]/g, '');

                    let fonts = [];
                    let blocks = resp.matchAll(/@font-face{[^{}]+}/g);
                    for (const block of blocks) {
                        const base64 = block[0].match(/url\(["']?([^"']+)["']?\)/);
                        const name = block[0].match(/font-family:["']?([^;'"]+)["']?;/);
                        const style = block[0].match(/font-style:([^;]+);/);
                        const weight = block[0].match(/font-weight:([^;]+);/);
                        if (!base64 || !name) throw new Error('failed to parse font');
                        fonts.push({
                            name: name[1],
                            style: style ? style[1] : 'normal',
                            weight: weight ? weight[1] : 'normal',
                            base64: base64[1]
                        })
                    }

                    for (const font of fonts) {
                        doc.addFileToVFS(`${font.name}.ttf`, font.base64.slice(font.base64.indexOf(',') + 1));
                        doc.addFont(`${font.name}.ttf`, font.name, font.style, font.weight);
                    }
                }

                const downloadPDF = async (arr) => {
                    let pageRangearr = [...Array(creader.readerDocData.showPage).keys()];
                    var pageRange;
                    if(arr!=null){
                       pageRange = arr;
                    }else{
                        pageRange = pageRangearr;
                    }
                    const version = 6;

                    showStatus('正在加载', 0);

                    // 强制加载所有页面
                    creader.loadNextPage(Infinity, true);
                    console.debug('[+] pages:', creader.renderPages);

                    const jspdf = await loadJsPDF();

                    let doc;
                    for (let i = 0; i < pageRange.length; i++) {
                        if(pageRange[i] >= creader.renderPages.length) {
                            console.warn('[!] pageRange[i] >= creader.renderPages.length, skip...');
                            continue;
                        }

                        showStatus('正在准备', ((i + 1) / pageRange.length) * 100);
                        const page = creader.renderPages[pageRange[i]];

                        // 缩放比例设为 1
                        page.pageUnDamageScale = page.pageDamageScale = () => 1;

                        if (creader.readerDocData.readerType === 'html_view')
                            await page.loadXreaderContent()

                        if (creader.readerDocData.readerType === 'txt_view')
                            await page.loadTxtContent()

                        if (['new_view', 'xmind_view'].includes(creader.readerDocData.readerType)) {
                            page.readerInfo = await page.readerInfoDataSource.requestIfNeed(i);
                            page.parsePPT();
                        }

                        if (page.readerInfo.pageInfo.version !== version) {
                            throw new Error(`脚本已失效: 文库版本号=${page.readerInfo.pageInfo.version}, 脚本版本号=${version}`);
                        }

                        const pageSize = [page.readerInfo.pageInfo.width, page.readerInfo.pageInfo.height]
                        if (!doc) {
                            doc = new jspdf.jsPDF(pageSize[0] < pageSize[1] ? 'p' : 'l', 'pt', pageSize);
                        } else {
                            doc.addPage(pageSize);
                        }

                        showStatus('正在下载图片');
                        page._pureImg = await loadImage(page.picSrc);

                        showStatus('正在加载字体');
                        await loadFont(doc, page);

                        showStatus('正在绘制');
                        for (const node of page.nodes) {
                            await drawNode(doc, page, node);
                        }

                        if(page._pureImg?.src) URL.revokeObjectURL(page._pureImg.src);
                        page._pureImg?.remove();
                    }

                    doc.save(`${unsafeWindow?.pageData?.title?.replace(/ - 百度文库$/, '') ?? '百度文库文档'}.pdf`);
                }

                // 添加需要用到的样式
                async function injectUI() {
                    const pdfButton = `<div class="s-btn-pdf"><div class="s-btn-img" ></div> <span>下载文档</span></div>`
                    const statusOverlay = `<div class="s-top s-top-status"><div class="s-panel"><div class="s-progress-wrapper"><div class="s-progress"></div></div><div class="s-status" style=""><div class="s-text" style="">正在加载...</div><div class="s-progress-text">0%<div></div></div></div></div></div>`;
                    const messageOverlay = `<div class="s-top s-top-message"><div class="s-message">testtest</div></div>`;

                    document.body.insertAdjacentHTML('afterbegin', statusOverlay);
                    document.body.insertAdjacentHTML('afterbegin', messageOverlay);
                    document.body.insertAdjacentHTML('beforeend', pdfButton);
                    document.head.appendChild(document.createElement('style')).innerHTML = `
            .s-btn-pdf {
              background: #0b1628;
              box-shadow: 0 2px 8px 0 #ddd;
              border-radius: 23px;
              width: 122px;
              height: 45px;
              line-height: 45px;
              text-align: center;
              cursor: pointer;
              position: fixed;
              top: 150px;
              right: 42px;
              z-index: 999;
            }

            .s-btn-pdf:hover {
              background-color: #fff;
              cursor: pointer;
            }
            .s-btn-pdf span{
              font-size: 14px;
              color: #d0b276;
              line-height: 14px;
              font-weight: 700;
            }
            .s-btn-img {
               background: url(https://wkstatic.bdimg.com/static/ndpcwenku/static/ndaggregate/img/gold-arrow-down.2a7dd761ebe866f57483054babe083bd.png) no-repeat;
               width: 18px;
               height: 18px;
               background-position: -1px 5px;
               background-size: cover;
               display: inline-block;
            }
            .s-top {
              position: fixed;
              top: 0;
              left: 0;
              bottom: 0;
              right: 0;
              z-index: 2000;
              padding-top: 40vh;
              display: none;
            }

            .s-top.s-top-message {
              text-align: center;
            }

            .s-message {
              background-color: #000000aa;
              color: white;
              padding: 8px 14px;
              text-align: center;
              font-size: 18px;
              border-radius: 6px;
              display: inline-block;
            }

            .s-top.s-top-status {
              z-index: 1000;
              cursor: wait;
              background-color: rgba(0, 0, 0, 0.4);
              backdrop-filter: blur(10px) saturate(1.8);
            }

            .s-top.show {
              display: block;
            }

            .s-panel {
              background: white;
              width: 90%;
              max-width: 480px;
              border-radius: 12px;
              padding: 14px 24px;
              margin: 0 auto;
            }

            .s-progress-wrapper {
              height: 24px;
              border-radius: 12px;
              width: 100%;
              background-color: #eeeff3;
              overflow: hidden;
              margin-bottom: 12px;
            }

            .s-progress {
              background-color: #54be99;
              height: 24px;
              width: 0;
              transition: width 0.2s ease;
            }

            .s-status {
              display: flex;
              font-size: 14px;
            }

            .s-text {
              flex-grow: 1;
              color: #5f5f5f;
            }

            .s-progress-text {
              color: #54be99;
              font-weight: bold;
            }
          `;
                }

                injectUI();
                const addMain = async (json)=>{
                    document.head.appendChild(document.createElement('style')).innerHTML = `
            .main-left{
              width: 367px;
            }
            .zhihu-scan{
               width:180px;
			   display:inline-block;
			   text-align: center;
               margin-right: 40px;
            }
			.zhihu-scan img{
				width: 140px;
				margin: 0 5px 10px 5px;
			}
			.zhihu-scan h1{
				font-size: 18px;
				font-weight: bold;
				margin: 0px 0 20px 0;
			}
			.zhihu-scan p{
			  margin: 0;
			  color: #666;
			  font-size: 14px;
			}
         `;
                    let defaultpassword = "";
                    if (localStorage.password && (Date.now() - localStorage.passwordTime) < 17280000) {
                        defaultpassword = localStorage.password;
                    } else {
                        localStorage.password = "";
                    }
                    let contenthtml ="";
                    contenthtml +='<form class="zhihu-form" style="height: 255px;"><div class="main-left">'
                    contenthtml +='<div class="zhihu-form-item"> <label class="zhihu-form-label">分批下载</label><div class="zhihu-input-inline" style="display:flex"><input id="start" type="number"  placeholder="开始" class="zhihu-input"><span style="line-height: 38px;margin: 0 10px;">-</span><input id="end" type="number" placeholder="结束" class="zhihu-input"></div></div>'
                    contenthtml +='<div class="zhihu-form-item" style="color: #acaeb5;"><div class="zhihu-input-block"><p>不填默认下载全部页数</p></div></div>'
                    contenthtml +='<div class="zhihu-form-item"> <label class="zhihu-form-label">验证码</label><div class="zhihu-input-inline"><input id="plcode" value="'+defaultpassword+'"  placeholder="请输入验证码" class="zhihu-input"></div></div>'
                    contenthtml +='<div class="zhihu-form-item" style="color: #acaeb5;"><div class="zhihu-input-block"><p>关注公众号获取</p></div></div>'
                    contenthtml +='<div class="zhihu-form-item"> <label class="zhihu-form-label">脚本推荐</label><div class="zhihu-input-inline"><a target="_blank" style="display: inline-block;height: 38px;line-height: 38px;text-decoration: none;font-size: 12px;color: #3e9677;" href="https://greasyfork.org/scripts/444713-%E6%99%BA%E7%8B%90-%E5%85%A8%E7%BD%91vip%E8%A7%86%E9%A2%91%E8%A7%A3%E6%9E%90%E6%97%A0%E5%B9%BF%E5%91%8A%E6%92%AD%E6%94%BE-%E6%94%AF%E6%8C%81b%E7%AB%99%E5%A4%A7%E4%BC%9A%E5%91%98%E7%95%AA%E5%89%A7-%E8%A7%86%E9%A2%91%E6%89%B9%E9%87%8F%E4%B8%8B%E8%BD%BD-%E5%85%A8%E7%BD%91%E7%8B%AC%E5%88%9B%E8%87%AA%E7%94%B1%E9%80%89%E6%8B%A9%E8%87%AA%E5%8A%A8%E8%A7%A3%E6%9E%90%E6%8E%A5%E5%8F%A3-%E7%9F%AD%E8%A7%86%E9%A2%91%E6%97%A0%E6%B0%B4%E5%8D%B0%E4%B8%8B%E8%BD%BD-%E6%B7%98%E5%AE%9D-%E5%A4%A9%E7%8C%AB-%E4%BA%AC%E4%B8%9C%E4%BC%98%E6%83%A0%E5%88%B8%E6%9F%A5%E8%AF%A2-%E6%9B%B4%E5%A4%9A%E5%8A%9F%E8%83%BD%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0%E4%B8%AD/code/%E3%80%90%E6%99%BA%E7%8B%90%E3%80%91%E5%85%A8%E7%BD%91VIP%E8%A7%86%E9%A2%91%E8%A7%A3%E6%9E%90%E6%97%A0%E5%B9%BF%E5%91%8A%E6%92%AD%E6%94%BE%EF%BC%8C%E6%94%AF%E6%8C%81B%E7%AB%99%E5%A4%A7%E4%BC%9A%E5%91%98%E7%95%AA%E5%89%A7%E3%80%81%E8%A7%86%E9%A2%91%E6%89%B9%E9%87%8F%E4%B8%8B%E8%BD%BD%EF%BC%8C%E5%85%A8%E7%BD%91%E7%8B%AC%E5%88%9B%E8%87%AA%E7%94%B1%E9%80%89%E6%8B%A9%E8%87%AA%E5%8A%A8%E8%A7%A3%E6%9E%90%E6%8E%A5%E5%8F%A3%7C%E7%9F%AD%E8%A7%86%E9%A2%91%E6%97%A0%E6%B0%B4%E5%8D%B0%E4%B8%8B%E8%BD%BD%7C%E6%B7%98%E5%AE%9D%E3%80%81%E5%A4%A9%E7%8C%AB%E3%80%81%E4%BA%AC%E4%B8%9C%E4%BC%98%E6%83%A0%E5%88%B8%E6%9F%A5%E8%AF%A2%7C%E6%9B%B4%E5%A4%9A%E5%8A%9F%E8%83%BD%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0%E4%B8%AD.user.js">点击安装道客、原创力文档下载脚本</a></div></div>'
                    contenthtml +='<div class="zhihu-form-item"> <label class="zhihu-form-label">使用说明</label><div class="zhihu-input-inline"><a target="_blank" style="display: inline-block;height: 38px;line-height: 38px;text-decoration: none;font-size: 12px;color: #3e9677;" href="https://zhihuweb.com/help/wenku/down.html">点击查看说明</a></div></div>'
                    contenthtml +='</div><div class="zhihu-scan"><img src="http://cdn.wezhicms.com/uploads/allimg/20211215/1-21121500044Q94.jpg"><h1>验证码获取</h1>'
                    contenthtml +='<div style="font-size: 12px;color: #000;margin-left:15px;text-align: left;"><div style="line-height: 2;text-align: center;">微信扫描二维码关注公众号,回复"3"获取验证码</div></div></div></form>'
                    Wenku.open({
                        area: ['520', '380'],
                        title: `正在获取 ${unsafeWindow?.pageData?.title?.replace(/ - 百度文库$/, '') ?? '百度文库文档'}`,
                        shade: 0,
                        id:"wenkuset",
                        btn: ['取消', '下载PDF'],
                        content:contenthtml,
                        btn1: function(data) {
                            let passwordCode = data.querySelector("#plcode").value;
                            let startnum = data.querySelector("#start").value;
                            let endnum = data.querySelector("#end").value;
                            if(json.data.pwd == passwordCode){
                                if (passwordCode != localStorage.password) {
                                    localStorage.password = passwordCode;
                                    localStorage.passwordTime = Date.now();
                                }
                                exportPDF(startnum,endnum);
                                unsafeWindow['downloadPDF'] = exportPDF;
                            }else {
                                Toast('验证码错误,请重新输入!');
                            }

                        }
                    });
                }
                 const addUpdate = async (json)=>{
                 let contenthtml ="";
                    contenthtml +=`<div style="text-align: center;width: 100%;"><div style="font-size: 18px;font-weight: bold;margin: 15px;">${json.message}</div><div style="font-size: 12px;line-height: 24px;margin: 15px;color: #333;">更新日志${json.data.desc}</div></div>`
                    Wenku.open({
                        area: ['520', '220'],
                        title: "版本更新提示",
                        shade: 0,
                        id:"Updateset",
                        btn: ['取消', '去更新'],
                        content:contenthtml,
                        btn1: function(data) {
                              window.open(json.data.updateUrl)
                        }
                    });
                 }
                 const addtip = async (json)=>{
                 let contenthtml ="";
                    contenthtml +=`<div style="text-align: center;width: 100%;"><div style="font-size: 18px;font-weight: bold;margin: 15px;">下载失败</div><div style="font-size: 12px;margin: 15px;line-height: 24px;color: #333;">查看并按照教程中的常见问题中的“不出现下载按钮”的解决办法操作,教程地址:点击下方的查看教程按钮</div></div>`
                    Wenku.open({
                        area: ['520', '240'],
                        title: "错误提示",
                        shade: 0,
                        id:"tipset",
                        btn: ['取消', '查看教程'],
                        content:contenthtml,
                        btn1: function(data) {
                              window.open("https://zhihuweb.com/help/wenku/down.html#常见问题")
                        }
                    });
                 }
                const generateArray = (start, end) => {
                             return Array.from(new Array(end + 1).keys()).slice(start)
                }
                const exportPDF = async (startnum,endnum) => {
                    try {
                        let num;
                        if(startnum!=""&&endnum!=""){
                            if(parseInt(startnum)<=parseInt(endnum)){
                                if(parseInt(endnum)>creader.readerDocData.showPage||parseInt(startnum)<1){
                                    throw new Error('页码输入错误,结束页码大于可预览页数或者起始页码小于1');
                                    return
                                }else{
                                   let arr = generateArray(parseInt(startnum)-1,parseInt(endnum)-1);
                                    num = arr.length;
                                    await downloadPDF(arr);
                                    console.log(arr);
                                }
                            }else{
                                throw new Error('页码输入错误,结束页码小于或等于开始页码');
                                return
                            }
                        }else{
                          await downloadPDF();
                          num = creader.readerDocData.page;
                        }
                        showMessage(`已成功导出,共计 ${num} 页~`);
                    } catch (error) {
                        console.error('[x] failed to export:', error);
                        showMessage('导出失败:'+error?.message ?? error);
                    } finally {
                        hideStatus();
                    }
                }
                const resp = await request("GET","https://zhihuweb.com/update.json");
                if(!resp) return;
                var json = JSON.parse(resp);
                const checkUpdate = async ()=>{
                    if(json.data.version > scpritversion){
                        addUpdate(json)
                    }else{
                       if(creader){
                          addMain(json)
                       }else{
                          addtip();
                       }
                        
                        //exportPDF();
                       // unsafeWindow['downloadPDF'] = exportPDF;
                    }
                }
                document.querySelector('.s-btn-pdf').onclick = ()=>checkUpdate();
            });
        }
    }
    function User(){
      let userhtml = '<div id="user" style="position: fixed;top: 50%;left: 50%;width: 480px;max-width: 80%;height: 468px;border-radius: 10px;background-image: url(https://static.hitv.com/pc/img/601d3ee.png),url(https://static.hitv.com/pc/img/21b00eb.png);background-position: 0 0,100% 280px;background-repeat: no-repeat;background-color: #fff;-webkit-box-shadow: 0 0 80px rgba(0,0,0,.25);box-shadow: 0 0 80px rgba(0,0,0,.25);opacity: 1;-webkit-transform: translate(-50%,-50%);-ms-transform: translate(-50%,-50%);transform: translate(-50%,-50%);z-index: 99999;">';
        var btncss="margin: 0 90px;";
        var tybtncss="width: 180px;";
        userhtml += '<div style="margin-top: 45px;color: #222;font-weight: 700;font-size: 28px;text-align: center;">脚本使用协议</div>'
        userhtml += '<div style="width: 100%;height: 220px;margin: 35px auto 40px;overflow-x: hidden;overflow-y: scroll;">'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;感谢您对本脚本的信任,为了更好的使用本脚本,在此,我们郑重提醒您:</p>'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">1.有能力的情况,请大家支持正版</p>'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">2.本脚本仅用学习交流,请勿用于非法、商业用途,使用本脚本下载的内容请勿进行复制、传播等侵权行为</p>'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">3.脚本会在使用过程中,修改网站部分本地数据,未侵入及修改远程服务器内容</p>'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">4.下载内容均来自平台本身API接口,如果侵权请邮件(188872170@qq.com)联系删除。</p>'
        userhtml +='<p style="margin: 0 50px 5px;color: #777;font-weight: 400;font-size: 13px;line-height: 22px;word-break: break-all;text-align: justify;">5.点击我同意后,即已代表您已经充分了解相关问题,否则后果自负,特此声明!</p></div>'
        userhtml +='<div style="display: flex;'+btncss+'justify-content: space-between;"><button style="width: 100px;height: 45px;border: none;border-radius: 25px;outline: none;color: #fff;background: #ddd;font-weight: 700;font-size: 15px;line-height: 45px;" id="bty">不同意</button> <button style="'+tybtncss+'height: 45px;border: none;border-radius: 25px;outline: none;color: #fff;background: #ffa000;background: -webkit-gradient(linear,left top,right top,from(#ff5f00),to(#ffa000));background: -webkit-linear-gradient(left,#ff5f00,#ffa000);background: -o-linear-gradient(left,#ff5f00 0,#ffa000 100%);background: linear-gradient(90deg,#ff5f00,#ffa000);font-weight: 700;font-size: 15px;line-height: 45px;" id="ty">我同意</button></div></div>'
        console.log(userhtml)
        document.body.insertAdjacentHTML('afterbegin', userhtml);


        document.querySelector("#ty").addEventListener('click',function() {
            GM_setValue("isuser","1");
            window.location.reload();
        })
        document.querySelector("#bty").addEventListener('click',function() {
            GM_setValue("isuser","0");
            document.body.removeChild(document.querySelector("#user"));
        });
    }
    switch (window.location.host) {
        case 'wenku.baidu.com':
            if(GM_getValue("isuser") == 1){
                Wenku.Downdocs();
                Wenku.GetVip();
            }else{
                User();
            }
            break;
        case 'wk.baidu.com':
            Wenku.Downdocs();
            Wenku.GetVip();
            break;
        case 'item.taobao.com':
            qrname = "淘宝";
            nodeid = ["#J_PromoPrice"];
            goodid = Getgoodid("id");
            method = "taobao";
            action = "getlink";
            Getcoupon(goodid);
            console.log(goodid);
            console.log('已进入淘宝');
            break;
        case 'detail.tmall.com':
        case 'detail.tmall.hk':
        case 'chaoshi.detail.tmall.com':
            qrname = "天猫";
            nodeid = ["#J_PromoPrice",".Price--sale--1huSj6m",".Price--normal--t-x499v"];
            goodid = Getgoodid("id");
            method = "taobao";
            action = "getlink";
            Getcoupon(goodid);
            console.log(goodid);
            console.log('已进入天猫');
            break;
        case 'item.yiyaojd.com':
            qrname = "京东";
            nodeid = "#J-summary-top";
            goodid = geturlid(window.location.href);
            method = "jd";
            action = "getdetails";
            Getcoupon(goodid);
            console.log(goodid) ;
            console.log('已进入京东医药');
            break;
        case 'item.jd.com':
            qrname = "京东";
            nodeid = "#J-summary-top";
            goodid = geturlid(window.location.href);
            method = "jd";
            action = "getdetails";
            Getcoupon(goodid);
            console.log(goodid);
            console.log('已进入京东');
            break;
        case 'npcitem.jd.hk':
            qrname = "京东";
            nodeid = "#J-summary-top";
            goodid = geturlid(window.location.href);
            method = "jd";
            action = "getdetails";
            Getcoupon(goodid);
            console.log(goodid);
            console.log('已进入京东国际');
            break;
    }
    // Your code here...
})();