Greasy Fork

FanfictionQomplete

Loads all following chapters on fanfiction.net and strips off bloat.

目前为 2015-06-11 提交的版本。查看 最新版本

// ==UserScript==
// @name          FanfictionQomplete
// @description   Loads all following chapters on fanfiction.net and strips off bloat.
// @namespace     https://greasyfork.org/en/users/11891-qon
// @author        Qon
// @include       https://www.fanfiction.net/s/*/*
// @noframes
// @grant         none
// @license       Simple Public License 2.0 (SimPL) https://tldrlegal.com/license/simple-public-license-2.0-%28simpl%29
// @version 0.0.1.20150611163247
// ==/UserScript==

// javascript:var script=document.createElement("script");script.src="https://greasyfork.org/en/scripts/10182-fanfictionqomplete/code/fanfictionqomplete.js";document.body.appendChild(script);window.setTimeout(function(){document.runFFQomplete();},500);
// document.styleSheets[0].cssText = "";

if (Element.prototype.remove == undefined) {
    Element.prototype.remove = function() {
        this.parentNode.removeChild(this)
    }
}

function injectRunButton() {
    var lc = document.getElementsByClassName('lc')
    if (lc.length) {
        lc = lc[0]
        var btn = document.createElement('button')
        btn.setAttribute('onclick', 'document.runFFQomplete();')
        btn.setAttribute('class', 'btn')
        btn.setAttribute('style', 'margin-left:12px;margin-right:2px;')
        btn.setAttribute('title', 'Append all following chapters and remove unecessary bloat.')
        btn.innerHTML = 'Qomplete!'
        lc.appendChild(btn)
    }
}
injectRunButton()

document.runFFQomplete = function() {
    var re = /(^.*?fanfiction\.net\/s\/\d+\/)(\d+)(\/?[^#]*)/

    function urlGetChap(url) {
        var arr = re.exec(url)
        return arr[2]
    }

    function urlSetChap(url, n) {
        var arr = re.exec(url)
        return arr[1] + n + arr[3]
    }

    function inc(url) {
        var arr = re.exec(url)
        return arr[1] + (parseInt(arr[2]) + 1) + arr[3]
    }

    function chapFromPage(url, page) {
        var storytext = page.getElementById('storytext')
        if (storytext) {
            var wrap = page.createElement('div')
            wrap.setAttribute('class', 'wrap col' + (urlGetChap(url) % 6))
            wrap.setAttribute('id', urlGetChap(url))
            var pad = page.createElement('div')
            pad.setAttribute('class', 'pad')
            var chapdiv = page.createElement('div')
            chapdiv.setAttribute('class', 'chapter')
            var chapspan = page.createElement('span')
            chapspan.innerHTML = urlGetChap(url) + '. '
            var title = page.getElementsByTagName('title')[0]
            var chaptitle = page.createElement('a')
            chaptitle.setAttribute('href', url.replace(/#.*$/, ""))
            chaptitle.innerHTML = title.innerHTML
            chapdiv.appendChild(chapspan)
            chapdiv.appendChild(chaptitle)
            chapdiv.appendChild(document.createElement('hr'))
            chapdiv.appendChild(storytext)
            pad.appendChild(chapdiv)
            wrap.appendChild(pad)
            return wrap
        } else return null
    }
    body = document.getElementsByTagName('body')[0]
    body.setAttribute('style', '')
    head = document.getElementsByTagName('head')[0]
    var title = document.getElementsByTagName('title')[0]

    var profile_top = document.getElementById('profile_top')
    var chap_select = document.getElementById('chap_select')
    var chap = chapFromPage(document.location.href, document)

    var ptbuttons = profile_top.getElementsByTagName('button')
    if (ptbuttons.length) {
        ptbuttons[0].remove()
        for (; head.firstElementChild;) head.firstElementChild.remove();
        for (; body.firstElementChild;) body.firstElementChild.remove();
    }
    body.removeAttribute('style')

    var style = document.createElement('style')
    style.setAttribute('type', 'text/css')
    // select{display: inline-block;}\n\
    // select{height: 30px;line-height: 30px;}\n\
    style.innerHTML =
        'body{background-color:lime;color:#ccc;margin:0;padding:0;font-family:"Verdana";}\n\
        div.loading{}\n\
        button, select{border-radius:4px;padding:4px 12px;background: linear-gradient(to bottom, #333, #000);border-width: 1px;color:#ccc;background-color:#000;}\n\
        button:hover{background-image:none;}\n\
        .panel{text-align:center;}\n\
        div.wrap{max-width:1300px;margin:auto;padding:0px 5px 0px 5px;}\n\
        div.wrap:first-child{padding-top:5px;margin-top:50px;}\n\
        div.wrap:last-child{padding-bottom:5px;margin-bottom:50px;}\n\
        div.pad{background-color:#222;padding:50px;}\n\
        .chapter{}#profile_top{}img{float:left;}canvas{float:left;}\n\
        a:link{color:#a05;}a:visited{color:#555;}a:hover{color:#fff;}a:active{color:#a05;}\n\
        .col1{background-color:#f0f;background:linear-gradient(to bottom, #f0f, #f00);}\n\
        .col2{background-color:#f00;background:linear-gradient(to bottom, #f00, #ff0);}\n\
        .col3{background-color:#ff0;background:linear-gradient(to bottom, #ff0, #0f0);}\n\
        .col4{background-color:#0f0;background:linear-gradient(to bottom, #0f0, #0ff);}\n\
        .col5{background-color:#0ff;background:linear-gradient(to bottom, #0ff, #00f);}\n\
        .col0{background-color:#00f;background:linear-gradient(to bottom, #00f, #f0f);}\n'
    switch ((urlGetChap(document.location.href) % 6)) {
        case 1:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #f0f);}\n'
            break;
        case 2:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #f00);}\n'
            break;
        case 3:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #ff0);}\n'
            break;
        case 4:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #0f0);}\n'
            break;
        case 5:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #0ff);}\n'
            break;
        case 0:
            style.innerHTML += '.profile{background-color:#777;background:linear-gradient(to bottom, #fff, #00f);}\n'
            break;
    }
    head.appendChild(style)
    head.appendChild(title)

    var profile = document.createElement('div')
    profile.setAttribute('class', 'wrap profile')
    profile.setAttribute('id', 'profile')
    var pad = document.createElement('div')
    pad.setAttribute('class', 'pad')
    pad.appendChild(profile_top)
    profile.appendChild(pad)
    body.appendChild(profile)

    var panel = document.createElement('div')
    panel.setAttribute('class', 'panel')

    var tocbtn = document.createElement('button')
    tocbtn.setAttribute('onclick', 'window.toggleToc();')
    tocbtn.setAttribute('style', 'float:left;')
    tocbtn.innerHTML = 'Table of Contents'


    panel.appendChild(tocbtn)

    window.toggleToc = function() {
        var e = document.getElementById('toc')
        if (e.style.display == 'none') {
            e.style.display = 'block'
        } else {
            e.style.display = 'none'
        }
    }

    var widthbtn = document.createElement('button')
    widthbtn.setAttribute('onclick', 'window.toggleWidth();')
    // widthbtn.setAttribute('style', 'position: absolute;display:flex; margin: 0 auto;')
    widthbtn.setAttribute('class', 'center')
    widthbtn.innerHTML = 'Page Width'
    panel.appendChild(widthbtn)

    window.toggleWidth = function() {
        var e = document.getElementById('widthstyle')
        if (e) e.remove()
        else {
            var s = document.createElement('style')
            s.setAttribute('id', 'widthstyle')
            s.innerHTML = 'div.wrap{max-width:100%;}'
            head.appendChild(s)
        }
    }

    chap_select.setAttribute('onchange', 'if(this.options[this.selectedIndex].value < ' + urlGetChap(document.location.href) + '){' +
        chap_select.getAttribute('onchange') +
        '}' + ' else {document.getElementById(\'\'+this.options[this.selectedIndex].value).scrollIntoView();}'
    )
    chap_select.setAttribute('style', 'float:right;')
    panel.appendChild(chap_select)

    document.getElementById('profile').firstChild.appendChild(panel)

    var toc = document.createElement('div')
    toc.setAttribute('class', 'pad')
    toc.setAttribute('id', 'toc')
    toc.style.display = 'none'
    toc.style.paddingTop = '0px'
    document.getElementById('profile').appendChild(toc)

    function tocAppend(s, n) {
        var toc = document.getElementById('toc')
        var a = document.createElement('a')
        a.setAttribute('href', '#' + n)
        a.innerHTML = s
        toc.appendChild(document.createElement('br'))
        toc.appendChild(a)
    }

    tocAppend('Chapter ' + urlGetChap(document.location.href) + '.', urlGetChap(document.location.href))

    body.appendChild(chap)

    function loadQomplete() {
        var a = document.getElementsByClassName('skiptranslate')
        for (; a.length;) {
            a[0].remove()
        }
        document.getElementsByTagName('body')[0].style.backgroundColor = '#000'
    }

    function appendChapterFromURL(url) {
        var oReq = new XMLHttpRequest();
        oReq.onload = function() {
            var xmlDoc = new DOMParser().parseFromString(this.responseText, "text/html")
            var url = this.responseURL ? this.responseURL : this.responseURLfallback
            if (!url) {
                console.log('Error: Response has no responseURL field!')
            }

            var chap = chapFromPage(url, xmlDoc)
            if (chap) {
                body.appendChild(chap)
                tocAppend('Chapter ' + urlGetChap(url) + '.', urlGetChap(url))
                window.setTimeout(function() {
                    appendChapterFromURL(inc(url))
                }, 0)
            } else loadQomplete()
        }
        oReq.responseURLfallback = url
        oReq.open("get", url, true)
        oReq.send()
    }

    appendChapterFromURL(inc(document.location.href))
}
// document.runFFQomplete()