E-Hentai Automated Downloads

Automates downloads through the Doggie Bag Archiver

当前为 2015-02-11 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           E-Hentai Automated Downloads
// @description    Automates downloads through the Doggie Bag Archiver
// @include        http://g.e-hentai.org/*
// @include        http://exhentai.org/*
// @include        http://*/*automatedEHDL=*
// @run-at         document-start
// @author         etc
// @version        1.2
// @namespace https://greasyfork.org/users/2168
// ==/UserScript==

var automating = (window.location.href.indexOf('automatedEHDL') != -1);

var addMetadata = function(url,metadata) {
    return url +
        (url.indexOf('?') != -1 ? '&' : '?') + 'automatedEHDL=' + metadata.nonce +
        '&automatedTorrent=' + (metadata.isTorrent ? 1 : 0);
};
       
var getMetadata = function(url) {
    var metadata = url.match(/automatedEHDL=(\d+).*automatedTorrent=(\d)/);
    return { nonce: metadata[1], isTorrent: metadata[2] == '1' };
};

if (automating) {

    var clear     = function() { for (var i=0;i<10;++i) clearTimeout(i); };
    var abort     = function(reason) { parent.postMessage({ type: 'failure', nonce: metadata.nonce, reason: reason },'*'); };
    var heartbeat = function() { parent.postMessage({ type: 'heartbeat', nonce: metadata.nonce },'*'); };

    var metadata = getMetadata(window.location.href), target;

    if (window.location.href.indexOf('archive') != -1)
        document.addEventListener('DOMSubtreeModified',clear,false);

    var onLoad = function() {

        for (var i=0;i<100;++i) clearTimeout(i);

        target = document.evaluate('.//a[starts-with(text(),"' + (metadata.isTorrent ? 'Torrent' : 'Archive') + ' Download")]',document,null,9,null).singleNodeValue;
        if (target !== null) {
            if (metadata.isTorrent && /\( 0 \)/.test(target.innerHTML)) abort('could not find any torrent');
            else {
                heartbeat();
                var url = target.getAttribute('onclick').match(/'(.+?)'/)[1];
                window.location.replace(addMetadata(url,metadata));
            }
            return;
        }

        // download confirmation popup
        target = document.evaluate('.//input[@value="Download Archive"]',document,null,9,null).singleNodeValue;
        if (target !== null) {
            heartbeat();
            target.parentNode.parentNode.action = addMetadata(target.parentNode.parentNode.action,metadata);
            target.click();
            return;
        }

        // server location popup
        target = document.evaluate('.//script[contains(text(),"gotonext")]',document,null,9,null).singleNodeValue;
        if (target !== null) {
            heartbeat();
            var url   = target.innerHTML.match(/document.location = "(.+?)"/)[1];
            var delay = target.innerHTML.match(/(\d+)\)/)[1];
            document.removeEventListener('DOMSubtreeModified',clear,false);
            setTimeout(function() { window.location.replace(addMetadata(url,metadata)); },parseInt(delay,10));
            return;
        }
        
        // download ready popup
        target = document.evaluate('.//a[text()="Click Here To Start Downloading"]',document,null,9,null).singleNodeValue;
        if (target !== null) {
            parent.postMessage({ type: 'success', nonce: metadata.nonce, url: target.href },'*');
            return;
        }

        // torrent page
        target = document.evaluate('.//input[@name="torrent_info"]',document,null,9,null).singleNodeValue;
        if (target != null) {
            var targets = Array.prototype.slice.call(document.querySelectorAll('[name="gtid"] + table'),0);
            targets = targets.map(function(x) {
                var link = x.querySelector('a').href;
                var data = x.textContent.match(/Seeds:\s*(\d+)(?:.|\n)*Peers:\s*(\d+)/);
                return { link: link, seeds: parseInt(data[1],10), peers: parseInt(data[2],10) };
            });
            targets = targets.sort(function(a,b) { return b.seeds - a.seeds; });
            if (targets.length === 0) abort('could not find any torrent');
            else if (targets[0].seeds === 0) abort('could not find any seeded torrent');
            else parent.postMessage({ type: 'success', nonce: metadata.nonce, url: targets[0].link },'*');
            return;
        }

        // we really shouldn't be here
        abort('No viable option found. Perhaps you\'re not logged in?\nCurrent URL: ' + window.location.href);

    };

    if (document.readyState == 'complete') onLoad();
    else window.addEventListener('load',onLoad,false);

} else {

    var downloadData = { }, downloadQueue = [ ];

    var loadingGIF =
        'R0lGODlhEgASAMQaAHl5d66urMXFw3l5dpSUk5WVlKOjoq+vrsbGw6Sko7u7uaWlpbm5t3h4doiIhtLSz4aGhJaWlsbGxNHRzrC' +
        'wr5SUkqKiobq6uNHRz4eHhf///wAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAaACwAAAAAEgASAAAFaq' +
        'AmjmRplstyrkmbrCNFaUZtaFF0HvyhWRZNYVgwBY4BEmFJOB1NlYpJoYBpHI7RZXtZZb4ZEbd7AodFDIYVAjFJJCYA4ISoI0hyu' +
        'UnAF2geDxoDgwMnfBoYiRgaDQ1WiIqPJBMTkpYaIQAAIfkEBQoAGgAsAQABABAAEAAABWSgJo4aRZEoeaxHOiqKFsyBtizopV9y' +
        'nfwJ0o43MhgNKAYjZbGQJBLXKBLRIK4IaWFbEHgFUoKYoPFKRZUK6fFIORwojBxDytgzpDkdANDc8SQTExp8fBoQEGcDiwNnJA0' +
        'NLiEAACH5BAUKABoALAEAAQAQABAAAAVloCaOmqKQKHmtVzpKksa2FIUiOKIxjHb8B5JgKCAFjgHUMHUkPR6u0WKhwVgx0YQ2cc' +
        'W6DGCDZjKJiiwWEgCQikRQ6zWpQC+QBviBxuHQEP4EKA0NGhmGGRoVFWaHiGYjEBAuIQAAIfkEBQoAGgAsAQABABAAEAAABWSgJ' +
        'o6aJJEoiaxIOj6PJsyCpigopmNyff0X0o43AgZJk0mKwSABAK4RhaJ5PqOH7GHAHUQD4ICm0YiKwCSHI7VYoDLwDClBT5Di8khE' +
        'Y+gbUBAQGgWEBRoWFmYEiwRmJBUVLiEAACH5BAUKABoALAEAAQAQABAAAAVloCaO2vOQKImtWDoCgMa2koTCsDZNGuIjpIFwQBI' +
        'YBahGI2UkORyukUKhyVgz0Yv2csW6thcNBBIVMRikSCRFoaAK8ALpQD+QCHiCZrHQBP4BKBUVGgmGCX6BUQaMBmUkFhYuIQAAIf' +
        'kEBQoAGgAsAQABABAAEAAABWagJo4aAJAoaZrp6DjaIA/a86BZnmlNo2FADEm3GwWFJAgkNZmQIpHWSCLRFK4FKWKLIHgJUoFYo' +
        'KlUpCIxabFIKRSohDxButgvJIPeoKFQNHd4JBYWGgeHBxoMDGgBjgFoJI4tIQAAIfkEBQoAGgAsAQABABAAEAAABWSgJo6a45Ao' +
        'ma1ZOkaRxrYAgBZ4oUGQVtckgpBAGhgHqEol1WiQFgvX6PHQJK4JKWaLMXgNWq7GYpGKJhMShZKSSFCH+IGEqCNIgXxAo1BoBIA' +
        'CKHkaF4YXf4JSh4hmIwwMLiEAACH5BAUKABoALAEAAQAQABAAAAVloCaOWhSRKFmsRToui0bMhOY4aKInWlVpmWCGZCgaSMIhyW' +
        'JJQSAkCsU1AgA0h+yBarUGvgHqYDzQfKmiRoOkUKQeD9RlfiFh7hgSvS6RaPB5JAwMGgiGCBoTE2gCjQJoJI0uIQAAOw==';

    var icons = {
        download : 'M8.037,11.166L14.5,22.359c0.825,1.43,2.175,1.43,3,0l6.463-11.194c0.826-1.429,0.15-2.598-' +
            '1.5-2.598H9.537C7.886,8.568,7.211,9.737,8.037,11.166z',
        torrent  : 'M22.404,13.585c0-5.319-4.313-9.631-9.632-9.631c-5.32,0-9.632,4.313-9.632,9.631c0,4.1,2.5' +
            '67,7.593,6.177,8.982l-1.818-8.45l-0.514-2.388L6.075,7.505L9.6,6.746l1.303,6.059c0.352,1.636,1.0' +
            '94,2.514,2.316,2.25c0.967-0.208,1.377-0.995,1.487-1.597c0.049-0.228,0.013-0.51-0.047-0.786l-1.4' +
            '43-6.705L16.74,5.21l1.646,7.651c0.662,3.077,2.454,3.548,2.454,3.548s-2.419,0.521-3.433,0.738c-1' +
            '.012,0.219-1.694-1.591-1.694-1.591l-0.07,0.015c-0.288,0.785-0.613,2.06-3.127,2.602c-0.184,0.039' +
            '-0.364,0.064-0.542,0.083l1.064,4.948C18.232,23.063,22.404,18.814,22.404,13.585z',
        picker   : 'M22.727,18.242L4.792,27.208l8.966-8.966l-4.483-4.484l17.933-8.966l-8.966,8.966L22.727,18.242z',
        done     : 'M2.379,14.729 5.208,11.899 12.958,19.648 25.877,6.733 28.707,9.561 12.958,25.308z'
    };

    var getIcon = function(name,color) {
        return 'url("data:image/svg+xml,<svg viewBox=\'0 0 30 30\' preserveAspectRatio=\'true\' xmlns=\'http' +
            '://www.w3.org/2000/svg\'><path fill=\'' + color + '\' d=\'' + icons[name] + '\'/></svg>")';
    };

    var createButton = function(data) {
        var result = document.createElement(data.hasOwnProperty('type') ? data.type : 'a');
        if (data.hasOwnProperty('class')) result.className = data.class;
        if (data.hasOwnProperty('title')) result.title = data.title;
        if (data.hasOwnProperty('onClick')) result.addEventListener('click',data.onClick,false);
        if (data.hasOwnProperty('parent')) data.parent.appendChild(result);
        if (data.hasOwnProperty('target')) result.setAttribute('target',data.target);
        if (data.hasOwnProperty('style'))
            result.style.cssText = Object.keys(data.style).map(function(x) { return x + ': ' + data.style[x] + 'px'; }).join('; ');
        return result;
    };

    var start = function() {

        // button generation (thumbnail list)
        var thumbnails = document.querySelectorAll('.id3 > a'), n = thumbnails.length;
        while (n --> 0) {
            var bottom = Math.max(0,parseInt(thumbnails[n].parentNode.style.height,10) - thumbnails[n].firstChild.height);
            var right  = Math.max(0,0.5 * (200 - thumbnails[n].firstChild.width));
            createButton({ class: 'automatedButton downloadLink', title: 'Automated download', target: thumbnails[n].href,
                style: { bottom: bottom, right: right }, onClick: requestDownload, parent: thumbnails[n] });
            createButton({ class: 'automatedButton torrentLink', title: 'Torrent download', target: thumbnails[n].href,
                style: { bottom: bottom, left: 1 }, onClick: requestDownload, parent: thumbnails[n] });
        }

        // button generation (gallery)
        var bigThumbnail = document.querySelector('#gd1 > img');
        if (bigThumbnail !== null) {
            var bottom = bigThumbnail.parentNode.parentNode.clientHeight - bigThumbnail.offsetTop - bigThumbnail.height - 1;
            var right  = bigThumbnail.parentNode.parentNode.clientWidth - bigThumbnail.offsetLeft - bigThumbnail.width - 2;
            var left   = bigThumbnail.offsetLeft + 1;
            createButton({ class: 'automatedButton downloadLink', title: 'Automated download', target: window.location.href,
                style: { bottom: bottom, right: right }, onClick: requestDownload, parent: bigThumbnail.parentNode });
            createButton({ class: 'automatedButton torrentLink', title: 'Torrent download', target: window.location.href,
                style: { bottom: bottom, left: left }, onClick: requestDownload, parent: bigThumbnail.parentNode });
        }

        // button generation (row list)
        var rows = document.querySelectorAll('.it5 > a'), n = rows.length;
        while (n --> 0) {
            var div = createButton({ type: 'div', class: 'automatedPicker', onClick: requestDownload, parent: rows[n].parentNode });
            var picker = createButton({ type: 'div', parent: div });
            createButton({ type: 'div', class: 'automatedInline torrentLink', title: 'Torrent download', 
                target: rows[n].href, parent: picker });
            createButton({ type: 'div', class: 'automatedInline downloadLink', title: 'Automated download',
                target: rows[n].href, parent: picker });
        }

        // message listener
        window.addEventListener('message',function(message) {
            var data = message.data;
            if (!downloadData.hasOwnProperty(data.nonce)) return;
            if (data.type == 'heartbeat') onHeartbeat(data);
            else if (data.type == 'success') onSuccess(data);
            else onFailure(data);
        },false);

        // document style
        var style = document.createElement('style');
        style.innerHTML =
            '.automatedButton { display: none; position: absolute; text-align: left; cursor: pointer; padding: 8px;' +
                'color: white; margin-right: 1px; font-size: 20px; line-height: 11px; }' +
            '.downloadLink  { background-image: ' + getIcon('download','rgb(0,0,0)') + '; background-color: rgba(98,220,151,1); }' +
            '.torrentLink  { background-image: ' + getIcon('torrent','rgb(0,0,0)') + '; background-color: rgba(98,182,210,1); }' +
            '.torrentLink:not(.requested) { background-position: 2px 2px; }' +
            '.requested  { background-image: ' + getIcon('done','rgb(0,0,0)') + '; }' +
            '.requested, .working { background-color: rgba(255,143,113,1); }' +
            '.automatedButton.downloadLink  { border-radius: 0 0 5px 0 !important; width: 12px; height: 12px; }' +
            '.automatedButton.torrentLink  { border-radius: 0 0 0 5px !important; width: 12px; height: 12px; }' +
            '#gd1 > .automatedButton { border-radius: 0 0 0 0 !important; }' +
            '.working { background-image: url(data:image/gif;base64,' + loadingGIF + ') !important; background-repeat: no-repeat; }' +
            '.automatedInline.working { background-position: 3px 3px; }' +
            '.automatedButton.working { width: 18px; height: 18px; font-size: 0px; background-position: 5px 5px; padding: 5px !important; }' +
            '.automatedPicker { background-image: ' + getIcon('picker','rgb(252,0,97)') + '; width: 16px;' + 
                'height: 16px; float: left; cursor: pointer; }' +
            '.automatedButton:hover, .automatedInline:hover { background-color: rgba(255,199,139,1) !important; color: black !important; }' +
            '*:hover > .automatedButton, .automatedButton.working, .automatedButton.requested { display: block !important; }' +
            '.EHADiframe { width: 0px !important; height: 0px !important; opacity: 0 !important; }' +
            '.automatedPicker > div { display: none; z-index: 2; position: absolute; top: -4px; text-align: center; }' +
            '.automatedPicker:hover > div, .automatedPicker > div:hover { display: block; }' +
            '.automatedInline { padding: 3px; border: 1px solid black; width: 17px; height: 17px; display: inline-block; }' +
            '.automatedInline:first-child { border-right: none !important; }';
        document.head.appendChild(style);

    };

    var startDownload = function(url) {
        downloadQueue.push(url);
        doDownload(false);
    };

    var doDownload = function(force) {
        if (doDownload.inhibit && !force) return;
        if (downloadQueue.length === 0) {
            doDownload.inhibit = false;
            return;
        }
        doDownload.inhibit = true;
        var a = document.createElement('a');
        // don't use display: none as some versions of firefox don't like it
        a.style.cssText = 'width: 0px; height: 0px; overflow: hidden; white-space: nowrap; visibility: hidden;';
        a.href = downloadQueue.splice(0,1)[0];
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        setTimeout(function() { doDownload(true); },1000);
    };

    var onHeartbeat = function(message) {
        generateTimeout(message.nonce);
    };

    var onSuccess = function(message) {
        var data = downloadData[message.nonce];
        document.body.removeChild(data.iframe);
        data.button.className = data.button.className.replace(/working/,'requested');
        clearTimeout(data.timeout);
        delete downloadData[message.nonce];
        startDownload(message.url);
    };

    var onFailure = function(message) {
        var data = downloadData[message.nonce];
        document.body.removeChild(data.iframe);
        data.button.className = data.button.className.replace(/\s?working/,'');
        clearTimeout(data.timeout);
        delete downloadData[data.nonce];
        alert('Something went wrong. Reason: ' + message.reason);
    };
    
    var generateTimeout = function(nonce) {
        if (!downloadData.hasOwnProperty(nonce)) return;
        clearTimeout(downloadData[nonce].timeout);
        downloadData[nonce].timeout = setTimeout(function() {
            onFailure({ nonce: nonce, reason: 'Operation timed out. Try again or download manually.' });
        },10000);
    };

    var requestDownload = function(e) {
        if (/working|requested/.test(e.target.className)) return; 
        e.preventDefault();
        e.target.className += ' working';
        var isTorrent = /torrentLink/.test(e.target.className);
        var gallery   = e.target.getAttribute('target');
        var nonce     = Math.floor(Math.random() * (1<<30));
        var iframe    = document.createElement('iframe');
        downloadData[nonce] = { button: e.target, iframe: iframe, timeout: null };
        generateTimeout(nonce);
        document.body.appendChild(iframe);
        iframe.className = 'EHADiframe';
        iframe.src = addMetadata(gallery,{ nonce: nonce, isTorrent: isTorrent });
    };

    window.addEventListener('load',start,false);

}