pixiv images direct link

By azu_re Last update Jan 11, 2012 — Installed 16,331 times.

There are 15 previous versions of this script.

// ==UserScript==
// @name           pixiv images direct link
// @namespace      http://web.zgo.jp/
// @description    pixivのフルサイズへのリンクをつける。AutoPagerize対応
// @include        http://www.pixiv.net/*
// @include        http://www.pixort.net/*
// @exclude        http://www.pixiv.net/member_illust.php?mode=manga&illust_id=*
// ==/UserScript==
var XPath = {
    cache:null,
    reset:function () {
        this.cache = {__proto__:null};
    },

    get:function (context, expr, type) {
        var x = new XPathEvaluator();
        var cache = this.cache, evaluator;
        if (expr in cache) {
            evaluator = cache[expr];
        } else {
            evaluator = cache[expr] = x.createExpression(expr, null);
        }
        return evaluator.evaluate(context, type, null);
    },

    has:function (context, expr) {
        return this.get(context, expr, XPathResult.BOOLEAN_TYPE).booleanValue;
    },

    first:function (context, expr) {
        return this.get(context, expr, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
    },

    last:function (context, expr) {
        var all = this.get(context, expr, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
        return all.snapshotItem(all.snapshotLength - 1) || null;
    },

    all:function (context, expr) {
        var all = this.get(context, expr, XPathResult.ORDERED_NODE_ITERAATE_TYPE);
        var ret = [];
        for (var i; (i = all.iterateNext()) !== null;) {
            ret.push(i);
        }
        return ret;
    }
};
XPath.reset();

// http://less.carbonfairy.org/post/1414938831/url
var dispatcher = {
    location:window.location,
    stash:[],

    connect:function (paths, action) {
        if (paths || paths === 0) {
            paths = paths.valueOf();
            if (!(typeof paths == 'object' && !(paths instanceof RegExp))) // webkit: typeof RegExp == 'function'
                paths = { pathname:paths };
            dispatcher.stash.push([paths, action]);
        }
        return dispatcher;
    },

    and:function () {
        var stash = dispatcher.stash,
                length = stash.length;
        length && (stash[length - 1][2] = true);
        return dispatcher;
    },

    dispatch:function (location) {
        location = location || dispatcher.location;
        var stash = dispatcher.stash,
                params = {};
        for (var i = 0, c; c = stash[i]; ++i) {
            var paths = c[0], action = c[1], chain = c[2];
            var matched = false;
            for (var k in paths) {
                var v = paths[k];
                var path = location[k];
                if (typeof path === "undefined") continue;
                var m = dispatcher.match(v, path);
                matched = !!m;
                if (matched) {
                    params[k] = m;
                } else {
                    break;
                }
            }
            if (matched) {
                if (action)
                    action(params);
                if (!chain) break;
            }
            else if (chain)
                break;
        }
        dispatcher.clear();
        return dispatcher;
    },

    match:function (value, path) {
        var ret;
        if (value instanceof RegExp)
            ret = value.exec(path) || false;
        else {
            value = value.toString();
            ret = (path.indexOf(value) != -1) && value;
        }
        return ret;
    },

    clear:function () {
        dispatcher.stash = [];
        return dispatcher;
    }
};
// Autopagerize時に使う関数
var autopageMake;
// URL dispatcher
dispatcher.connect({
            host:/^www\.pixiv\.net/,
            search:/mode=manga_tb/
        },
        function () { // manga thumb page
            //autopageMake = makeFullSizeLink;
            //manga_tb()
        }).connect({// Ranking
            host:/www\.pixiv\.net/,
            pathname:/ranking\.php/
        },
        function () {
            autopageMake = makeFullSizeLinkTypeDelay;
            makeFullSizeLinkTypeDelay(document);
        }).connect({// other
            host:/www\.pixiv\.net/
        },
        function () {
            autopageMake = makeFullSizeLink;
            makeFullSizeLink(document);
        }).connect({ // http://www.pixort.net/index.php?word=%E6%9D%B1%E6%96%B9&mode=2week
            host:/^www\.pixort\.net/
        },
        function () {
            autopageMake = makeFullSizeLink_pixort;
            makeFullSizeLink_pixort(document);
        }).dispatch(location);

// pixort.net
function makeFullSizeLink_pixort(doc) {
    var links = XPath.all(doc, ".//a");
    var sourcePixivReg = /www\.pixort\.net\/image\//;
    for (var i = 0, l = links.length; i < l; i++) {
        if (links[i].hasChildNodes()) {
            var linkChild = links[i].firstChild;
            if (linkChild.tagName == "IMG" && !sourcePixivReg.test(linkChild.src)) {
                var full_img = document.createElement("a");
                full_img.setAttribute("style", "color:#3F658C;");
                full_img.innerHTML = "[S]";
                // http://www.pixort.net/img/img23/77gl/15126014_s.jpg →
                full_img.href = linkChild.src.replace(/^.+pixort\.net\/img\/([^\/]+)\/([^\/]+\/[^\/]+)_[ms]\.(jpe?g|gif|png)/
                        , "http://$1.pixiv.net/img/$2.$3");
                insertAfter(full_img, links[i]);
            }
        }
    }
}
// 検索画面 、その他
function makeFullSizeLinkTypeDelay(doc) {
    GM_addStyle(String(<>
        <![CDATA[
        article > .GM_pixiv_dicrect_img_link{
            position:absolute;
            bottom:0;
        }
        .GM_pixiv_dicrect_img_link{
            color:#3F658C;
            margin:0 3px;
        }
    ]]></>));
    var sources = XPath.all(doc, './/img["data-src"]');
    var sourcePixivReg = /(source|ads)\.pixiv\.net/;
    for (var i = 0, l = sources.length; i < l; i++) {
        var source = sources[i];
        source = source.hasAttribute("data-src") && source.getAttribute("data-src");
        if (source) {
            var full_img = document.createElement("a");
            full_img.className = "GM_pixiv_dicrect_img_link";
            full_img.innerHTML = "[S]";
            full_img.href = source.replace(/(.+pixiv\.net\/img\/[^\/]+\/[^\/]+)_([ms]|100)\.(jpe?g|gif|png)/, "$1.$3");
            insertAfter(full_img, sources[i].parentNode.nodeName === "A" ? sources[i].parentNode : sources[i].parentNode.parentNode);
        }
    }
}
// member_illust.php?mode=medium
// 検索画面
function makeFullSizeLink(doc) {
    var links = XPath.all(doc, './/a');
    var sourcePixivReg = /(source|ads)\.pixiv\.net/;
    for (var i = 0, l = links.length; i < l; i++) {
        var linkChild = XPath.first(links[i], './/img');
        if (linkChild && !sourcePixivReg.test(linkChild.src)) {
            var full_img = document.createElement("a");
            full_img.setAttribute("style", "color:#3F658C;");
            full_img.innerHTML = "[S]";
            if (/mode=manga/.test(links[i].href)) {
                full_img.href = linkChild.src.replace(/(.+pixiv\.net\/img\/[^\/]+\/[^\/]+)_[ms]\.(jpe?g|gif|png)/, "$1_p0.$2");
            } else {
                full_img.href = linkChild.src.replace(/(.+pixiv\.net\/img\/[^\/]+\/[^\/]+)_([ms]|100)\.(jpe?g|gif|png)/, "$1.$3");
            }
            insertAfter(full_img, links[i]);
        }
    }
}
// 漫画サムネイル
function manga_tb() {
    getMangaPage(function (viewDOM) {
        var links = XPath.all(document, 'id("thumbnail")//a');
        for (var i = 0, l = links.length; i < l; i++) {
            var link = links[i];
            if (link.hasChildNodes()) {
                if (link.firstChild.tagName == "IMG") {
                    var pageNo = link.href.split("#")[1]; // pageN
                    var img = XPath.first(viewDOM, 'id("' + pageNo + '")//a[not(../span)]/img');
                    if (img) {
                        var full_img = document.createElement("a");
                        full_img.setAttribute("style", "color:#3F658C;");
                        full_img.innerHTML = "[S]";
                        full_img.href = img.src;
                        link.parentNode.parentNode.appendChild(full_img);
                    }
                }
            }
        }
    })
}
function getMangaPage(callback) {
    var href = location.href.replace("manga_tb", "manga");
    GM_xmlhttpRequest({
        method:'GET',
        url:href,
        headers:{
            'User-agent':'Mozilla/4.0 (compatible) Greasemonkey'
        },
        onload:function (responseDetails) {
            var DOMHTML = createDocumentFromString(responseDetails.responseText);
            callback(DOMHTML);
        }
    });
}
function insertAfter(newNode, node) {
    if (node.nextSibling === null) {
        node.parentNode.appendChild(newNode); // 末尾に追加
    } else {
        node.parentNode.insertBefore(newNode, node.nextSibling); // 基準ノードの後ろに追加
    }
}
// via http://github.com/hatena/hatena-bookmark-xul/blob/master/chrome/content/common/05-HTMLDocumentCreator.js
function createDocumentFromString(source) {
    var doc;
    try {
        doc = document.cloneNode(false);
        doc.appendChild(doc.importNode(document.documentElement, false));
    } catch (e) {
        doc = document.implementation.createHTMLDocument ?
                document.implementation.createHTMLDocument('hogehoge') :
                document.implementation.createDocument(null, 'html', null);
    }
    var range = document.createRange();
    range.selectNodeContents(document.documentElement);
    var fragment = range.createContextualFragment(source);
    var headChildNames = {title:true, meta:true, link:true, script:true, style:true, /*object: true,*/ base:true/*, isindex: true,*/};
    var child, head = doc.getElementsByTagName('head')[0] || doc.createElement('head'),
            body = doc.getElementsByTagName('body')[0] || doc.createElement('body');
    while ((child = fragment.firstChild)) {
        if (
                (child.nodeType === doc.ELEMENT_NODE && !(child.nodeName.toLowerCase() in headChildNames)) ||
                        (child.nodeType === doc.TEXT_NODE && /\S/.test(child.nodeValue))
                )
            break;
        head.appendChild(child);
    }
    body.appendChild(fragment);
    doc.documentElement.appendChild(head);
    doc.documentElement.appendChild(body);
    return doc;
}
document.body.addEventListener('AutoPagerize_DOMNodeInserted', function (evt) {
    var node = evt.target;
    autopageMake(node);
}, false);