BinB阅读器捕获脚本(v016061)

用于binb阅读器v016061版本的漫画的获取脚本

// ==UserScript==
// @name         BinB阅读器捕获脚本(v016061)
// @namespace    summer-script
// @version      0.2.2
// @description  用于binb阅读器v016061版本的漫画的获取脚本
// @author       summer
// @match        https://gammaplus.takeshobo.co.jp/_files/*
// @match        https://www.comicride.jp/viewer/*
// @exclude      https://www.comicride.jp/viewer/*/HTML5/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    var btn = createBtn();
    var jsonUrls = getJsonUrls();
    btn.addEventListener('click', function() {
        run(jsonUrls, btn);
    });

    function run(jsonUrls, btn, counter) {
        var jsonPath = jsonUrls.shift();
        if (undefined === jsonPath) {
            btn.innerText = '获取完毕';
            return;
        }
        var coords, ptimg;
        counter = counter ? counter : 0;
        counter++;
        jsonGet(jsonPath).then(function(ret) {
            ptimg = ret;
            coords = decodeCoords(ptimg.views[0].coords, ptimg.resources);
            var imgPath = ptimg.resources[coords[0].resid].src;
            var imgSrc = getImgUrl(imgPath, jsonPath);
            return loadImg(imgSrc);
        })
        .then(function(img) {
            btn.innerText = '正在获取...(剩余'+jsonUrls.length+'页)';
            var orgwidth = ptimg.views[0].width;
            var orgheight = ptimg.views[0].height;
            var prefix = document.title;
            var filename = prefix + '-' + counter + '.png';
            var cv = toCanvas(img, coords, orgwidth, orgheight);
            toFile(cv, filename);
            run(jsonUrls, btn, counter);
        });
    }

    function loadImg(src) {
        var func = function(resolve) {
            var img = new Image();
            img.onload = function() {
                resolve(img);
            };
            img.onerror = function() {
                console.log('image['+src+'] load fail, retrying...');
                setTimeout(function() {
                    func(resolve);
                }, 2000);
            };
            img.src = src;
        }
        return new Promise(func);
    }

    function toCanvas(img, coords, width, height) {
        var cv = document.createElement('canvas');
        cv.width = width;
        cv.height = height;
        var ctx = cv.getContext('2d');
        for(var i in coords) {
            ctx.drawImage(
                img,
                coords[i].xsrc,
                coords[i].ysrc,
                coords[i].width,
                coords[i].height,
                coords[i].xdest,
                coords[i].ydest,
                coords[i].width,
                coords[i].height
            );
        }
        return cv;
    }

    function toFile(canvas, filename) {
        canvas.toBlob(function(blob) {
            var url = URL.createObjectURL(blob);
            var a = document.createElement('a');
            a.download = filename;
            a.href = url;
            a.click();
        });
    }

    function jsonGet(path) {
        var func = function(resolve) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function() {
                if (XMLHttpRequest.DONE !== xhr.readyState) {
                    return;
                }
                if (200 !== xhr.status) {
                    return;
                }
                var ret;
                try {
                    ret = JSON.parse(xhr.responseText);
                } catch(err) {
                    ret = false;
                }
                resolve(ret);
            };
            xhr.open('GET', path);
            xhr.send();
        };
        return new Promise(func);
    }

    function createBtn() {
        var wrap = document.createElement('div');
        wrap.style.top = '6px';
        wrap.style.right = '8px';
        wrap.style.zIndex = '302';
        wrap.style.position = 'fixed';
        document.body.appendChild(wrap);
        var btn = document.createElement('button');
        btn.style.marginLeft = '8px';
        btn.style.padding = '8px';
        btn.style.background = '#fff';
        btn.style.border = '1px solid #aaa';
        btn.style.borderRadius = '4px';
        btn.style.minWidth = '112px';
        btn.style.color = '#000';
        btn.style.float = 'right';
        btn.style.cursor = 'pointer';
        btn.innerText = '下载';
        wrap.appendChild(btn);
        return btn;
    }

    function getJsonUrls() {
        var misc = document.getElementById('content')
                           .getElementsByTagName('div');
        var contents = [];
        for (var i = 0; i < misc.length; i++) {
            if (misc[i].hasAttribute('data-ptimg')) {
                contents.push(misc[i].getAttribute('data-ptimg'));
            }
        }
        return contents;
    }

    function decodeCoords(coordsData, resources) {
        var coordData, coordsNum = [];
        for (var i = 0; i < coordsData.length; i++) {
            coordData = coordsData[i];
            var reg = /^([^:]+):(\d+),(\d+)\+(\d+),(\d+)>(\d+),(\d+)$/;
            var n = coordData.match(reg);
            if (!n) {
                return false;
            }
            var r = n[1];
            if (!(r in resources)) {
                return false;
            }
            coordsNum.push({
                resid: r,
                xsrc: parseInt(n[2], 10),
                ysrc: parseInt(n[3], 10),
                width: parseInt(n[4], 10),
                height: parseInt(n[5], 10),
                xdest: parseInt(n[6], 10),
                ydest: parseInt(n[7], 10)
            });
        }
        return coordsNum;
    }

    function getImgUrl(imgPath, jsonPath) {
        var r;
        if (imgPath.indexOf('http://') + imgPath.indexOf('https://') !== -2) {
            r = imgPath;
        } else if ("" === imgPath) {
            r = jsonPath;
        } else if ("/" === imgPath[0]) {
            r = imgPath;
        } else if (".." === jsonPath){
            r = "../" + imgPath;
        } else if (jsonPath.match(/\/\.\.$/)){
            r = jsonPath + "/" + imgPath;
        } else if (-1 === jsonPath.indexOf("/")) {
            r = imgPath;
        } else {
            r = jsonPath.replace(/\/[^\/]*$/, "/") + imgPath;
        }
        if ("" === r) {
            return "";
        }
        var n = [];
        var i = r.replace(/\/+/g, "/")
                 .replace(/\/\.$/, "/")
                 .replace(/(^|\/)\.\.$/, "$1../")
                 .split("/").filter(function(t, i, n) {
                    return "." !== t
                  });
        for (r = 0; r < i.length; r++) {
            if (".." === i[r]) {
                if (n.length > 0) {
                    var e = n.pop();
                    "" === e ? n.push("") : ".." === e && n.push("..", "..")
                } else {
                    n.push("..");
                }
            } else {
                n.push(i[r]);
            }
        }
        var s = n.join("/");
        "" === s && (s = ".");
        return s;
    }
})();