sciDownload

适配ipad端userscripts

目前為 2022-03-14 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        sciDownload
// @namespace   http://tampermonkey.net/
// @version     2.2
// @description 适配ipad端userscripts
// @author      Polygon
// @icon        data:image/png;base64,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
// @match       *://*/*
// @grant       unsafeWindow
// @grant       GM_xmlhttpRequest
// @grant       GM_download
// @grant       GM_addStyle
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_openInTab
// @grant       unsafeWindow
// @grant       window.close
// @connect     *
// @run-at      document-idlm
// ==/UserScript==
(function() {
    'use strict'
    const notification = (function() {
        'use strict';
        GM_addStyle(`
            #notification {
                box-sizing: border-box;
                position: fixed;
                left: calc(50% - 365.65px / 2);
                display: flex;
                flex-direction: row;
                align-items: center;
                justify-content: center;
                height: 50px;
                background-color: #ff7675;
                border-radius: 50px;
                padding: 0 0px 0px 20px;
                top: -50px;
                transition: top .5s ease-out;
                z-index: 9999999999;
            }
            #notification .content {
                display: flex;
                align-items: center;
                justify-content: center;
                color: white;
                font-size: 25px;
            }
            #notification .closeBox {
                margin: 0 10px;
                transform: rotate(90deg);
                cursor: pointer;
            }
            #notification .closeBox .progress {
                margin: 0 10px;
                cursor: pointer;
            }
            #notification .closeBox .progress .circle {
                stroke-dasharray: 100;
                animation: progressOffset 0s linear;
            }
            @keyframes progressOffset {
                from {
                    stroke-dashoffset: 100;
                }
                to {
                    stroke-dashoffset: 0;
                }
            }
        `)
        return {
            open(info, timeout, autoClose=true) {
                let eles = document.querySelectorAll('#notification')
                for (let i=0;i<eles.length;i++) {
                    this.close(eles[i])
                }
                this.box = document.createElement('div')
                this.box.setAttribute('id', 'notification')
                this.box.innerHTML = `
                    <div class="content"></div>
                    <svg class="closeBox" width="40" height="40">
                        <g class="close" style="stroke: white; stroke-width: 2; stroke-linecap: round;">
                            <line x1="13" y1="13" x2="27" y2="27"/>
                            <line x1="13" y1="27" x2="27" y2="13"/>
                        </g>
                        <g class="progress" fill="transparent" stroke-width="3">
                            <circle class="background" cx="20" cy="20" r="16" stroke="rgba(255,255,255,0.15)"/>
                            <circle class="circle" cx="20" cy="20" r="16" stroke="rgba(255,255,255,1)"/>
                        </g>
                    </svg>
                    `
                document.body.appendChild(this.box)
                this.box.querySelector('.content').innerHTML = info
                let width = getComputedStyle(this.box).width
                this.box.style.left = `clac(50%-${width}/2)`
                this.box.querySelector('.closeBox .progress .circle').style['animation-duration'] = `${timeout}s`
                this.box.style.top = '100px'
                this.box.querySelector('.closeBox .progress').addEventListener('click', () => {
                    console.log('you close...')
                    this.close()
                    console.log('you clear...')
                })
                if (autoClose) {
                    setTimeout(() => {
                        console.log('timeout close...')
                        this.close()
                        console.log('timeout clear ...')
                    }, timeout * 1000)
                }
            },
            close(ele=null) {
                if (!ele) {ele=this.box}
                ele.style['transition-duration'] = '.23s'
                ele.style['transition-timing-function'] = 'eaer-out'
                ele.style.top = '-50px'
                setTimeout(() => {
                    try {
                        document.body.removeChild(this.box)
                    } catch {
                        console.log('clear')
                    }
                }, 1000)
            }
        }
    })();

    const utils = {
        api: 'http://muise.icu:5000/sciDownload',
        doiRegex: new RegExp(/10\.\d{4,9}\/[-\._;\(\)\/:A-z0-9]+/),
        pdfRegex: /(content-type|Content-Type).+(pdf|binary|application|stream)/g,
        timeout: 25,
        autoMax: {b: true, time: 1},
        scihubURL: 'sci-hub.ee',
        // 适配ipad,userscript暂不支持GM_getValue,GM_setValue
        get switchState() {
            if (typeof(GM_getValue) == 'undefined') {
                return this._switchSate
            } else {
                return GM_getValue('sciDownload-state', 'max')
            }
        },
        set switchState(value) {
            if (typeof(GM_setValue) == 'undefined') {
                this._switchSate = value
            } else {
                GM_setValue('sciDownload-state', value)
            }
        },
        _switchSate: 'max',
        color:
        {
            success: '#e74c3c',
            flash: '#00b894',
            fail: '#2c3e50'
        },
        svg:
        {
            doi: `<svg class="progressBox" width="40" height="40">
                <g fill="transparent" stroke-width="2.5">
                    <circle class="progress-background" cx="20" cy="20" r="11" stroke="rgba(255,255,255,0.23)"/>
                    <circle class="progress" cx="20" cy="20" r="11" stroke="rgba(255,255,255,1)" stroke-linecap="round"/>
                </g>
            </svg>`,
            pdf: `<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2519" width="30" height="30"><path d="M478.08 192.192a58.88 58.88 0 0 1 46.208 23.168c23.104 32.064 21.312 99.84-8.832 199.68A536.832 536.832 0 0 0 625.664 557.44c37.312-7.04 74.688-12.416 112-12.416 83.52 1.792 96 41.024 94.144 64.128 0 60.544-58.688 60.544-88.896 60.544v0.064a226.048 226.048 0 0 1-131.52-53.504c-72.832 16-142.144 39.168-211.456 67.712C344.96 782.08 293.312 832 248.96 832c-8.96 0-19.584-1.792-26.752-7.168A52.48 52.48 0 0 1 192 776.704c0-16 3.52-60.608 172.352-133.568a1267.776 1267.776 0 0 0 94.208-221.056c-21.312-42.752-67.584-147.84-35.584-201.344 10.688-19.648 32-30.272 55.168-28.544z m-118.4 475.84c-42.688 20.736-95.232 58.368-90.112 82.368 3.392 16 21.888 10.56 55.424-16.384 21.056-27.072 24.512-41.088 34.688-65.984z m386.304-79.808c-17.152 0-32.384 0-49.536 7.68 19.072 19.2 29.504 28.608 48.64 32.448 13.312 3.84 39.104 10.752 46.72-9.28 7.68-19.968-7.616-30.848-45.824-30.848zM494.08 492.8a2572.16 2572.16 0 0 1-46.592 104.704l104.704-34.88c-21.76-22.272-41.344-43.392-58.112-69.824z m-16.64-223.488c-10.496 1.664-16.192 15.04-18.88 24.512-5.504 27.008 8.96 57.088 27.072 78.528 14.912-22.528 18.688-43.328 12.928-73.92-6.976-20.48-14.016-30.208-21.12-29.12z" fill="#ffffff" p-id="2520"></path></svg>`,
            switch: `<svg width="40" height="40">
                <g stroke="white" stroke-width="3" stroke-linecap="round">
                    <line x1="10" y1="20" x2="30" y2="20"/>
                    <line class="switch" x1="10" y1="20" x2="30" y2="20"/>
                </g>
            </svg>`
        },
        style() {
            let div = document.createElement('div')
            div.innerHTML = this.svg.doi
            div.style.opacity = '0'
            document.body.appendChild(div)
            try{
                this.progressTotaLength = div.querySelector('.progress').getTotalLength()
            } catch {
                this.progressTotaLength = 68.66967010498047
            }
            document.body.removeChild(div)
            return `
            #sciDownloadBox {
                display: flex;
                position: fixed;
                height: 40px;
                bottom: 75px;
                font-family: NexusSans,Arial,Helvetica,Lucida Sans Unicode,Microsoft Sans Serif,Segoe UI Symbol,STIXGeneral,Cambria Math,Arial Unicode MS,sans-serif;
                font-size: 18px;
                cursor: pointer;
                box-shadow: 0px 0px 20px rgba(0, 0, 0, .1);
                transition: left .23s ease-out, opacity .23s, right .23s ease-out;
                z-index: 9999999999;
            }
            #sciDownloadBox * {
                box-sizing: border-box;
            }
            #sciContent {
                position: relative;
                overflow: hidden;
                box-sizing: border-box;
                display: flex;
                height: 40px;
                align-items: center;
                justify-content: space-around;
                vertical-align: middle;
                white-space: nowrap;
                color: white;
                background-color: ${this.color.fail};
                opacity: 0.72;
                transition: width .23s ease-out, opacity .23s, background-color .23s;
            }
            #sciContent[loading] #sciState .progress {
                opacity: 0;
            }
            #sciContent[loading]::before {
                content: '';
                position: absolute;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                opacity: 0;
                background-color: white;
                z-index: -1;
                animation: loading 2.3s linear infinite;
            }
            @keyframes loading {
                from {
                    opacity: 0;
                }
                50% {
                    opacity: 0.3;
                }
                to {
                    opacity: 0;
                }
            }
            #sciSwitch {
                width: 40px;
                height: 40px;
                color: white;
                background-color: #00b894;
                opacity: 0.72;
                transition: width .23s ease-out, opacity .23s;
                z-index: 1;
            }
            #sciContent #sciState {
                position: relative;
                overflow: hidden;
                display: flex;
                align-items: center;
                justify-content: center;
                width: 40px;
                height: 40px;
                opacity: 1;
            }
            #sciContent #sciText {
                position: relative;
                overflow: hidden;
                height: 100%;
                display: flex;
                align-items: center;
                justify-content: center;
                color: white;
                padding-left: 5px;
                padding-right: 10px;
                opacity: 1;
                text-decoration: none;
                transition: width .23s ease-out;
            }
            #sciContent:hover {
                opacity: 0.99 !important;
            }
            #sciSwitch:hover {
                opacity: 1 !important;
            }
            /* left svg progress */
            #sciContent #sciState .progressBox {
                transform: rotate(-90deg);
            }
            #sciContent #sciState .progress {
                stroke-dasharray: ${this.progressTotaLength};
                stroke-dashoffset: ${this.progressTotaLength};
                transition: stroke-dashoffset .23s linear;
            }
            #sciContent[progress] #sciState .progress {
                animation: progressOffset ${this.timeout}s linear forwards;
            }
            @keyframes rotator {
                from {
                    transform: rotate(-90deg);
                }
                to {
                    transform: rotate(180deg);
                }
              }
            #sciContent[download-noprogress] #sciState .progressBox {
                animation: rotator 2.3s linear infinite;
            }
            @keyframes dash {
                from {
                    stroke-dashoffset: ${this.progressTotaLength};
                }
                50% {
                    stroke-dashoffset: ${this.progressTotaLength / 4};
                    transform:rotate(135deg);
                }
                to {
                    stroke-dashoffset: ${this.progressTotaLength};
                    transform:rotate(450deg);
                }
            }
            #sciContent[download-noprogress] #sciState .progress {
                stroke-dashoffset: 0;
                transform-origin: center;
                animation: dash 2.3s ease-in-out infinite;
            }
            @keyframes progressOffset {
                from {
                    stroke-dashoffset: ${this.progressTotaLength};
                }
                to {
                    stroke-dashoffset: 0;
                }
            }
            @keyframes progressRecover {
                to {
                    stroke-dashoffset: ${this.progressTotaLength};
                }
            }
            /* progress animation */
            @keyframes progress {
                to {
                  width: 100%;
                }
            }
            /* switch button animation */
            #sciSwitch svg .switch {
                transform: rotate(0deg);
                transform-origin: center center;
                transition: transform .23s ease-out .15s;
            }
            /* ripple effect */
            #sciDownloadBox .ripple {
                position: absolute;
                background: #fff;
                transform: translate(-50%, -50%);
                pointer-events: none;
                border-radius: 50%;
                animation: ripple 1s linear;
            }
            @keyframes ripple{
                from {
                    width: 0px;
                    height: 0px;
                    opacity: 0.5;
                }
                to {
                    width: 500px;
                    height: 500px;
                    opacity: 0;
                }
            }
            `
        },
        initBox(doi) {
            let createBox = () => {
                this.sciDownloadBox = document.createElement('div')
                this.sciDownloadBox.setAttribute('id', 'sciDownloadBox')
                this.sciDownloadBox.innerHTML = `
                                                <div id="sciSwitch">${this.svg.switch}</div>
                                                <div id="sciContent">
                                                    <div id="sciState"></div>
                                                    <a id="sciText"></a>
                                                </div>
                                                `
                document.body.appendChild(this.sciDownloadBox)
                // 绑定变量
                this.sciContent = this.sciDownloadBox.querySelector('#sciContent')
                this.sciState = this.sciDownloadBox.querySelector('#sciState')
                this.sciText = this.sciDownloadBox.querySelector('#sciText')
                // 改变doi文字
                this.changeContent(this.svg.doi, doi)
                // 缓入准备
                this.sciDownloadBox.style.right = -this.getElementWidth(this.sciDownloadBox) + 'px'
                setTimeout(() => {
                    // 设置right属性,触发缓入动画
                    this.sciDownloadBox.style.right = '0px'
                }, 230)
                this.sciSwitch = this.sciDownloadBox.querySelector('#sciSwitch')
                // 最大化/最小化按钮点击事件绑定
                this.sciSwitch.addEventListener('click', this.switchEvent)
                // 涟漪效果点击事件
                this.sciState.addEventListener('click', this.rippleClickEvent)
                this.sciText.addEventListener('click', this.rippleClickEvent)
                // 当窗口调整时,自适应
                window.onresize = () => {
                    setTimeout(() => {
                        this.sciSwitch.click()
                        this.sciSwitch.click()
                    })
                }
            }
            // 添加sciTool逻辑
            if (this.sciDownloadBox) {
                // 存在,设置left属性缓出
                this.sciDownloadBox.style.left = getComputedStyle(utils.sciDownloadBox).left
                this.sciDownloadBox.style.left = document.body.clientWidth + 'px'
                GM_addStyle(`
                    #sciContent[progress] #sciState .progress {
                        animation: progressOffset 25s linear forwards;
                    }
                `)
                setTimeout(() => {
                    // 缓出结束,让其消失,并创建新的
                    this.sciDownloadBox.remove()
                    createBox.apply(this)
                }, 230);
            } else {
                // 可能首次打开页面,直接创建
                createBox.apply(this)
            }

        },
        rippleClickEvent(event) {
            // 这一步让sciState内svg的点击事件传播到sciState,而svg本身不产生动画效果
            let parent
            for (let i=0;i<event.path.length;i++) {
                if (event.path[i].id.match(/(sciText|sciState)/)) {
                    parent = event.path[i]
                    break
                }
            }
            let x = event.offsetX
            let y = event.offsetY
            let ripple = document.createElement("span")
            ripple.setAttribute('class', 'ripple')
            ripple.style.left = `${x}px`
            ripple.style.top = `${y}px`
            parent.appendChild(ripple)
            // timeout数值越大涟漪扩散越慢
            setTimeout(() => {
                ripple.remove()
            }, 1000)
            event.stopPropagation();
        },
        switchEvent(event) {
            if (utils.switchState == 'max') {
                utils.sciDownloadBox.style.left = getComputedStyle(utils.sciDownloadBox).left
                utils.sciDownloadBox.style.left = document.body.clientWidth - 40 * 2 + 'px'
                utils.sciDownloadBox.style.right = -utils.getElementWidth(utils.sciDownloadBox) + 'px'
                utils.sciSwitch.querySelector('svg .switch').style.transform = 'rotate(90deg)'
                utils.switchState = 'min'
            } else if (utils.switchState == 'min') {
                utils.sciDownloadBox.style.left = ''
                utils.sciDownloadBox.style.right = '0px'
                utils.sciSwitch.querySelector('svg .switch').style.transform = 'rotate(0deg)'
                utils.switchState = 'max'
            }
        },
        startProgress() {
            this.sciContent.setAttribute('progress', '')
            // 有progress属性的有进度条动画
            GM_addStyle(`
                /* 背景色进度条 */
                #sciContent[progress] #sciText::before {
                    content: "";
                    position: absolute;
                    right: 0;
                    bottom: 0;
                    height: 40px;
                    width: 0%;
                    background-color: ${this.color.flash};
                    opacity: 1;
                    z-index: -1;
                    animation: progress ${this.timeout}s linear forwards;
                }
            `)
        },
        getContentWidth(ele, content) {
            let oldContent = ele.innerHTML
            ele.innerHTML = content
            let width = this.getElementWidth(ele)
            ele.innerHTML = oldContent
            return width
        },
        getElementWidth(ele) {
            return parseFloat(window.getComputedStyle(ele).width.replace('px', ''))
        },
        changeContent(state, text, callback=null) {
            if (state) {this.sciState.innerHTML = state}
            let ele = this.sciText
            let oldWidth = this.getElementWidth(ele)
            let newWidth = this.getContentWidth(ele, text)
            ele.style.width = oldWidth + 'px'
            setTimeout(() => {
                ele.style.width = newWidth + 'px'
                ele.innerHTML = text
                setTimeout(() => {
                    ele.style.width = 'fit-content'
                    if (callback) {callback()}
                }, 230)
                if (this.switchState == 'min' & this.autoMax.b){
                    this.sciSwitch.click()
                    setTimeout(() => {
                        this.sciSwitch.click()
                    }, this.autoMax.time * 1000 > 230 ? this.autoMax.time * 1000 : 230)
                }
            }, 230)
        },
        getDoi() {
            let doi, select, res
            let selection = window.getSelection().toString()
            let sourceText = document.body.innerHTML
            res = selection.match(this.doiRegex)
            if (res) {
                doi = res[0]
                select = true
            } else {
                res = sourceText.match(this.doiRegex)
                if (res) {
                    doi = res[0]
                    select = false
                }
            }
            if (doi) {
                doi = doi.replace(/[\/\.]\w*?pdf/, '').split(';')[0]
            }
            return [doi, select]

        },
        LocalSearch(doi) {
            // 1 开启动画效果
            this.initBox(doi)
            setTimeout(() => {
                this.startProgress()
            }, 230)
            // 2 生成data,这里按顺序查询,不太会用js的并发只能按照顺序了,应该不会很慢
            let data = undefined
            let totalSource = 4
            let failSource = 0
            // 2.1 查询unpaywall
            let setData = (value) => {
                if (value.url) {
                    if (data == undefined) {
                        data = value
                    }
                } else {
                    failSource += 1
                }
            }
            const unpaywall = `https://api.unpaywall.org/v2/${doi}[email protected]`
            GM_xmlhttpRequest({
                method: 'GET',
                url: unpaywall,
                responseType: 'json',
                onload: function (res) {
                    const unpaywallData = res.response
                    let url
                    try {
                        url = unpaywallData['best_oa_location']['url_for_pdf'] || unpaywallData['best_oa_location']['url_for_landing_page']
                    } catch {
                        url = ''
                        if (Object.prototype.hasOwnProperty.call(unpaywallData, 'title')) {
                            console.log(`unpaywall: ${unpaywallData['title']}`)
                            researchgate(unpaywallData['title'])  // 交给researchgate
                        }
                    }
                    setData({
                        message: 'unpaywall.org',
                        url: url
                    })
                }
            })
            // 2.2 查询scihub
            const scihub = `https://${this.scihubURL}/${doi}`
            GM_xmlhttpRequest({
                method: 'GET',
                url: scihub,
                onload: function (res) {
                    let url = res.response.match(/\/\/(.+pdf)[^\'\"]/)
                    if (url) {
                        url = 'https://' + url[1]
                    } else {
                        url = ''
                    }
                    setData({
                        message: utils.scihubURL,
                        url: url
                    })
                }
            })
            // 2.3 查询researchgate
            let isConsistent = (s1, s2) => {
                if (s1 == null || s2 == null) return false
                let matchArray = [], strArray = [s1, s2]
                for (let i=0;i<strArray.length;i++) {
                    matchArray.push(strArray[i].toLowerCase().match(/\w+/g))
                }
                [s1, s2] = matchArray
                if (s1.length != s2.length) return false
                let b = true
                for (let i=0;i<s1.length;i++) {
                    if (s1[i] != s2[i]) return false
                }
                return b
            }
            let researchgate = (paperTitle) => {
                const url = `https://www.researchgate.net/search.SearchBox.html?query=${paperTitle}&activeTab=publication`
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    headers: {'accept': 'application/json'},
                    responseType: 'json',
                    onload: function (res) {
                        const resData = res.response['result']['state']['searchSearch']['publication']['items']
                        console.log(resData)
                        let url = ''
                        let i = 0
                        while (i < resData.length) {
                            let item = resData[i]
                            if (!Object.prototype.hasOwnProperty.call(item['urls'], 'download')){
                                console.log(`researchgate: no url`)
                            } else {
                                const pdfURL = 'https://www.researchgate.net/' + item['urls']['download']
                                // 标题是否一致
                                if (isConsistent(item['title'], paperTitle)) {
                                    url = pdfURL
                                    console.log(`researchgate[${i}]: best title`)
                                    console.log(paperTitle)
                                    console.log(item['title'])
                                    break
                                } else {
                                    console.log(`researchgate: not consistent`)
                                }
                            }
                            i += 1
                        }
                        setData({
                            message: 'researchgate.net',
                            url: url
                        })
                    }
                })
            }
            // 2.4 出版商地址
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://doi.org/${doi}`,
                onload: function (res) {
                    let publisherURL = res.finalUrl
                    // https://linkinghub.elsevier.com/retrieve/pii/S016980952100421X
                    if (publisherURL.includes('linkinghub.elsevier.com')) {
                        let pdfURL = 'https://www.sciencedirect.com/science/article/pii/' + publisherURL.match(/pii\/(.+)/)[1] + '/pdfft'
                        console.log(pdfURL)
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: pdfURL,
                            onload: function (res) {
                                let url = ''
                                res = res.response.match(/"(https?:\/\/pdf.+)"/)
                                if (res && res.length == 2) {
                                    url = res[1]
                                } else {
                                    url = ''
                                }
                                setData({
                                    message: 'sciencedirect.com',
                                    url: url
                                })
                            }
                        })
                    } else if (publisherURL.includes('springer.com')) {
                        let pdfURL = 'https://link.springer.com/content/pdf/' + publisherURL.match(/article\/(.+)/)[1] + '.pdf'
                        console.log(pdfURL)
                        let func = (res) => {
                            let url
                            let contentType = res.responseHeaders.match(/content-type:(.+)/)[1]
                            console.log(contentType)
                            if (contentType.includes('pdf')) {
                                url = pdfURL
                            } else {
                                url = ''
                            }
                            setData({
                                message: 'springer.com',
                                url: url
                            })
                        }
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: pdfURL,
                            onprogress: func,
                            onload: func
                        })
                    } else {
                        setData({
                            message: 'sciencedirect.com',
                            url: null
                        })
                    }
                    // 补充其他
                }
            })
            // 3 等待data结果,并提交至下一个函数
            let total = 0
            const interval = 10
            let id = setInterval(() => {
                if (data != undefined) {
                    console.log(data)
                    utils.getPdf(data, doi)
                    clearInterval(id)
                } else if (failSource == totalSource) {
                    data = {
                        message: 'NotSupport',
                        url: ''
                    }
                    utils.getPdf(data, doi)
                    clearInterval(id)
                } else if (total > this.timeout * 1000) {
                    data = {
                        message: 'Timeout',
                        url: ''
                    }
                    utils.getPdf(data, doi)
                    clearInterval(id)
                }
                total += interval
            }, interval)
        },
        getPdf(data, doi) {
            // 进入下载,收回timeout倒计时的进度条
            let progress = this.sciState.querySelector('svg .progress')
            let currentOffset = getComputedStyle(progress)['stroke-dashoffset']
            GM_addStyle(`
                #sciContent[progress] #sciState .progress {
                    stroke-dashoffset: ${currentOffset};
                    animation: progressRecover .23s linear;
                }
            `)
            setTimeout(() => {
                // 动画结束后改变sciContent状态
                this.sciContent.removeAttribute('progress')
            }, 230)
            this.changeContent(null, data.message)
            // api相应速度太快,可能清除不掉过一段时间才出现的进度条, 检测一秒钟
            let exit = true
            switch (data.message) {
                case 'NotSupport':
                    this.log('不支持该文章,退出...')
                    break
                case 'Timeout':
                    this.log('请求超时,退出...')
                    break
                default:
                    this.log('请求pdf中...')
                    exit = false
            }
            setTimeout(() => {
                progress.style['stroke-dashoffset'] =  '0'
            }, 230*2)
            if (exit) {
                return
            }
            utils.sciContent.style['background-color'] = utils.color.flash
            let openInTab = (url) => {
                if (typeof(GM_openInTab) == 'undefined') {
                    var a = document.createElement('a')
                    a.href = url
                    a.target = '_blank'
                    document.body.appendChild(a)
                    a.click()
                    a.remove()
                } else {
                    GM_openInTab(url, {active: false, insert: true})
                }
            }
            utils.sciText.onclick = () => { openInTab(data.url) }
            utils.sciState.onclick = () => { openInTab(data.url) }
            // 开始缓存同时尝试打开链接,可将下行反注释即可
            // window.open(pdfURL)
            let failSetting = () => {
                progress.style['stroke-dashoffset'] =  '0'
                utils.sciContent.style['background-color'] = utils.color.fail
            }
            let lastTime, currentTime, lastDone=0, currentDone, size
            setTimeout(() => {
                this.sciContent.setAttribute('loading', '')
                progress.style['stroke-dashoffset'] =  utils.progressTotaLength
            }, 230*2)
            GM_xmlhttpRequest({
                method: 'GET',
                url: data.url,
                responseType: 'blob',
                onprogress: function(res) {
                    utils.sciContent.removeAttribute('loading')
                    if (!res.responseHeaders.match(utils.pdfRegex)) {
                        failSetting()
                        return
                    }
                    // 波浪冲击效果待完成
                    let rippleUp = (opacity) => {
                        let ripple = document.createElement("span")
                        ripple.setAttribute('class', 'ripple')
                        ripple.style.backgroundColor = 'white'
                        ripple.style.zIndex = -1
                        ripple.style.opacity = opacity
                        ripple.style.left = `${utils.getElementWidth(utils.sciContent)}px`
                        ripple.style.top = '20px'
                        utils.sciContent.appendChild(ripple)
                        // timeout数值越大涟漪扩散越慢
                        setTimeout(() => {
                            ripple.remove()
                        }, 1E3)
                    }
                    currentTime = new Date().getTime()
                    currentDone = res.done
                    if (!lastTime | currentTime - lastTime >= 300) {
                        size = (currentDone - lastDone) / 1024 / 1024 * 5
                        rippleUp(size > 1 ? 1 : size)
                        lastTime = currentTime
                        lastDone = currentDone
                        let tip
                        if (res.lengthComputable) {
                            utils.sciContent.setAttribute('download-progress', '')
                            let percent = res.done / res.total
                            progress.style['stroke-dashoffset'] =  utils.progressTotaLength * (1- percent)
                            // 下载进度条
                            GM_addStyle(`
                                #sciContent[download-progress] #sciText::before {
                                    content: "";
                                    position: absolute;
                                    right: 0;
                                    bottom: 0;
                                    height: 40px;
                                    width: ${percent * 100}%;
                                    background-color: white;
                                    opacity: 0.5;
                                    z-index: -1;
                                    transition: width .23s linear;
                                }
                            `)
                            tip = `${(res.done / 1024 / 1024).toFixed(2)}M | ${(res.total / 1024 / 1024).toFixed(2)}M | ${(percent * 100).toFixed(2)}% | ${data.message}`
                        } else {
                            utils.sciContent.setAttribute('download-noprogress', '')
                            tip = `${(res.done / 1024 / 1024).toFixed(2)}M | --M | --% | ${data.message}`
                        }
                        utils.sciContent.setAttribute('title', tip)
                        utils.sciSwitch.setAttribute('title', tip)
                    }
                },
                onload: function(res) {
                    setTimeout(() => {
                        utils.sciContent.removeAttribute('loading')
                        if (!res.responseHeaders.match(utils.pdfRegex)) {
                            failSetting()
                            notification.open('pdf加载失败了,亲自点一下吧~', 3)
                            return
                        }
                        utils.sciContent.removeAttribute('download-progress')
                        utils.sciContent.removeAttribute('download-noprogress')
                        setTimeout(() => {
                            utils.sciContent.style['background-color'] = utils.color.success
                        }, 230);
                        console.log(res.response)
                        let fileURL = URL.createObjectURL(new Blob([res.response], {type: 'application/pdf'}))
                        let title = doi.split('/').slice(1).join('/')
                        let titleRes = res.responseHeaders.match(/filename=(.+)/)
                        if (titleRes) {
                            title = decodeURI(titleRes[1].split(';')[0]).replace('.pdf', '').replace('"', '').replace('"', '')
                        }
                        utils.sciText.removeAttribute('href')
                        utils.sciText.onclick = () => {
                            setTimeout(() => {
                                let win = window.open()
                                win.document.write(`<iframe name="${title}" src="${fileURL}" frameborder="0" style="border:0; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%;" allowfullscreen></iframe>`)
                                win.document.title = title
                            }, 1E3)
                        }
                        utils.log('缓存pdf成功')
                        utils.sciContent.style['background'] = utils.color.success
                        utils.changeContent(utils.svg.pdf, title)
                        utils.sciState.onclick = (event) => {
                            let aTag = document.createElement('a')
                            aTag.setAttribute('href', fileURL)
                            aTag.setAttribute('download', `${title}.pdf`)
                            aTag.click()
                        }
                    }, 230*3);
                }
            })
        },
        log(text) {
            console.log('[sciDownload]', text)
        }
    }
    try{
        GM_addStyle(utils.style())
    } catch {
        utils.log('添加style失败,退出...')
        return
    }
    let lastDoi = null
    let lastIsSelect = false
    setInterval(function () {
        let [doi, select] = utils.getDoi()
        if (!doi | doi == lastDoi | (lastIsSelect && !select)) {
            return
        }
        lastDoi = doi
        lastIsSelect = select
        let a = 'background: #00b894; color: #fff; opacity: 0.75;'
        let b = 'background: #2c3e50; color: #fff; opacity: 0.75;'
        console.log(`%c sciDownload %c ${doi} `, a, b)
        utils.LocalSearch(doi)
    }, 500)
})();