Zelluloza Dumper

Сохраняет фрагмент книги, доступный для чтения в формате fb2. Книги защищенные максимальной защито сохранет в виде картинок

当前为 2016-08-09 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Zelluloza Dumper
// @version      0.4
// @description  Сохраняет фрагмент книги, доступный для чтения в формате fb2. Книги защищенные максимальной защито сохранет в виде картинок
// @author       MadDAD
// @include  https://zelluloza.ru/books/*
// @namespace https://greasyfork.org/users/38856
// ==/UserScript==
//*************************************
var saveAs = saveAs || (function(view) {
    "use strict";
    // IE <10 is explicitly unsupported
    if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
        return;
    }
    var
        doc = view.document
        // only get URL when necessary in case Blob.js hasn't overridden it yet
        ,
        get_URL = function() {
            return view.URL || view.webkitURL || view;
        },
        save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"),
        can_use_save_link = "download" in save_link,
        click = function(node) {
            var event = new MouseEvent("click");
            node.dispatchEvent(event);
        },
        is_safari = /constructor/i.test(view.HTMLElement),
        is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent),
        throw_outside = function(ex) {
            (view.setImmediate || view.setTimeout)(function() {
                throw ex;
            }, 0);
        },
        force_saveable_type = "application/octet-stream"
        // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
        ,
        arbitrary_revoke_timeout = 1000 * 40 // in ms
        ,
        revoke = function(file) {
            var revoker = function() {
                if (typeof file === "string") { // file is an object URL
                    get_URL().revokeObjectURL(file);
                } else { // file is a File
                    file.remove();
                }
            };
            setTimeout(revoker, arbitrary_revoke_timeout);
        },
        dispatch = function(filesaver, event_types, event) {
            event_types = [].concat(event_types);
            var i = event_types.length;
            while (i--) {
                var listener = filesaver["on" + event_types[i]];
                if (typeof listener === "function") {
                    try {
                        listener.call(filesaver, event || filesaver);
                    } catch (ex) {
                        throw_outside(ex);
                    }
                }
            }
        },
        auto_bom = function(blob) {
            // prepend BOM for UTF-8 XML and text/* types (including HTML)
            // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
            if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
                return new Blob([String.fromCharCode(0xFEFF), blob], {
                    type: blob.type
                });
            }
            return blob;
        },
        FileSaver = function(blob, name, no_auto_bom) {
            if (!no_auto_bom) {
                blob = auto_bom(blob);
            }
            // First try a.download, then web filesystem, then object URLs
            var
                filesaver = this,
                type = blob.type,
                force = type === force_saveable_type,
                object_url, dispatch_all = function() {
                    dispatch(filesaver, "writestart progress write writeend".split(" "));
                }
                // on any filesys errors revert to saving with object URLs
                ,
                fs_error = function() {
                    if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
                        // Safari doesn't allow downloading of blob urls
                        var reader = new FileReader();
                        reader.onloadend = function() {
                            var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
                            var popup = view.open(url, '_blank');
                            if (!popup) view.location.href = url;
                            url = undefined; // release reference before dispatching
                            filesaver.readyState = filesaver.DONE;
                            dispatch_all();
                        };
                        reader.readAsDataURL(blob);
                        filesaver.readyState = filesaver.INIT;
                        return;
                    }
                    // don't create more object URLs than needed
                    if (!object_url) {
                        object_url = get_URL().createObjectURL(blob);
                    }
                    if (force) {
                        view.location.href = object_url;
                    } else {
                        var opened = view.open(object_url, "_blank");
                        if (!opened) {
                            // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
                            view.location.href = object_url;
                        }
                    }
                    filesaver.readyState = filesaver.DONE;
                    dispatch_all();
                    revoke(object_url);
                };
            filesaver.readyState = filesaver.INIT;

            if (can_use_save_link) {
                object_url = get_URL().createObjectURL(blob);
                setTimeout(function() {
                    save_link.href = object_url;
                    save_link.download = name;
                    click(save_link);
                    dispatch_all();
                    revoke(object_url);
                    filesaver.readyState = filesaver.DONE;
                });
                return;
            }

            fs_error();
        },
        FS_proto = FileSaver.prototype,
        saveAs = function(blob, name, no_auto_bom) {
            return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
        };
    // IE 10+ (native saveAs)
    if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
        return function(blob, name, no_auto_bom) {
            name = name || blob.name || "download";

            if (!no_auto_bom) {
                blob = auto_bom(blob);
            }
            return navigator.msSaveOrOpenBlob(blob, name);
        };
    }

    FS_proto.abort = function() {};
    FS_proto.readyState = FS_proto.INIT = 0;
    FS_proto.WRITING = 1;
    FS_proto.DONE = 2;

    FS_proto.error =
        FS_proto.onwritestart =
        FS_proto.onprogress =
        FS_proto.onwrite =
        FS_proto.onabort =
        FS_proto.onerror =
        FS_proto.onwriteend =
        null;

    return saveAs;
}(
    typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window

if (typeof module !== "undefined" && module.exports) {
    module.exports.saveAs = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
    define([], function() {
        return saveAs;
    });
}
//*************************************

function ImagePreloader(images, callback) {
    // store the call-back
    this.callback = callback;
    // initialize internal state.
    this.nLoaded = 0;
    this.nProcessed = 0;
    this.aImages = new Array();
    // record the number of images.
    this.nImages = images.length;
    // for each image, call preload()
    for (var i = 0; i < images.length; i++)
        this.preload(images[i]);
}

ImagePreloader.prototype.preload = function(image) {
    // create new Image object and add to array
    var oImage = new Image();
    this.aImages.push(oImage);
    // set up event handlers for the Image object
    oImage.onload = ImagePreloader.prototype.onload;
    oImage.onerror = ImagePreloader.prototype.onerror;
    oImage.onabort = ImagePreloader.prototype.onabort;
    // assign pointer back to this.
    oImage.oImagePreloader = this;
    oImage.bLoaded = false;
    // assign the .src property of the Image object
    oImage.src = image;
};
ImagePreloader.prototype.onComplete = function() {
    this.nProcessed++;

    my_getbyid("bookpg").innerHTML = 'Загружено страниц: ' + this.nProcessed + ' из ' + this.nImages;

    if (this.nProcessed == this.nImages) {
        this.callback(this.aImages, this.nLoaded);
    }
};
ImagePreloader.prototype.onload = function() {
    this.bLoaded = true;
    this.oImagePreloader.nLoaded++;

    this.oImagePreloader.onComplete();
};
ImagePreloader.prototype.onerror = function() {
    this.bError = true;
    this.oImagePreloader.onComplete();
};
ImagePreloader.prototype.onabort = function() {
    this.bAbort = true;
    this.oImagePreloader.onComplete();
};

//*************************************

function GetUserToken() {
    var UserToken = eval(document.getElementsByTagName("script")[8].text.split(';')[1].split(',')[5]);

    if (UserToken === undefined) {
        UserToken = eval(document.getElementsByTagName("script")[9].text.split(';')[1].split(',')[5]);
    }

    if (UserToken === undefined) {
        var URL = document.getElementsByClassName("taglnk2");
        for (var i = 0; i < URL.length; i++) {
            var xmlhttp = getXmlHttp();
            xmlhttp.open("GET", URL[i], false);

            if (xmlhttp.readyState == 1) {
                xmlhttp.setRequestHeader("Content-Type", "text/html");
                xmlhttp.send();
            }


            if (xmlhttp.status != 200) {
                alert(xmlhttp.status + ': ' + xmlhttp.statusText); // пример вывода: 404: Not Found
            } else {
                var doc = new DOMParser().parseFromString(xmlhttp.responseText, "text/html");
                UserToken = eval(doc.getElementsByTagName("script")[6].text.split(';')[1].split(',')[5]);

                if (UserToken === undefined)
                    UserToken = eval(doc.getElementsByTagName("script")[5].text.split(';')[1].split(',')[5]);

                if (UserToken !== undefined)
                    return UserToken;

            }

        }
    }

    return UserToken;
}

function MyAjax(obj, notused, par1, par2, par3, par4, append) {
    var xmlhttp = getXmlHttp();
    var params = "op=" + encodeURIComponent(par1) + "&par1=" + encodeURIComponent(par2) + "&par2=" + encodeURIComponent(par3) + "&par4=" + encodeURIComponent(par4);
    ajaxDone = 0;
    if (xmlhttp.readyState == 0) {
        xmlhttp.open("POST", "/ajaxcall/", false);
    }
    if (xmlhttp.readyState == 1) {
        xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlhttp.send(params);
    }

    if (xmlhttp.readyState == 4) {
        if (xmlhttp.status == 200) {
            ajaxDone = 1;
            if (obj != "") {
                var str = xmlhttp.responseText;
                if (par1 == "getbook") {
                    chp = str.split("<END>");
                    return chp;
                }
            }
        }
    }

}

function AllBook(book) {
    //var MaxProtection = my_getbyid("protected1").src !== '';

    var MaxProtection = false;
    if (!MaxProtection) {

        var pageHtml = "";
        var BookId = document.getElementById("gotobook").value;
        var PartId = document.getElementsByClassName("taglnk2")[0].href.split('/')[4];
        var UserToken = GetUserToken();
        var BookTitle = document.getElementsByClassName("booklnk4")[1].childNodes[0].innerHTML;
        var PartTitle = document.getElementsByClassName("taglnk2")[0].text;

        var series = "";
        var res = new RegExp('.*Серия: (.*)$', 'm').exec(document.getElementsByClassName('serie')[1].outerText);
        if (res !== null)
            series = res[1];

        pageHtml = '<?xml version="1.0" encoding="utf-8"?><FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink">';
        pageHtml += '<description><title-info><genre/><author><first-name>' + document.getElementsByClassName("txt")[5].text + '</first-name><last-name/></author>';
        pageHtml += '<book-title>' + BookTitle + '</book-title>';
        pageHtml += '<annotation><p>' + document.getElementsByTagName("meta", "")[4].content + '</p></annotation>';
        pageHtml += '<lang>ru</lang><src-lang>ru</src-lang>';
        pageHtml += '<sequence name="' + series + '" number="" />';
        pageHtml += '</title-info><document-info><author><nickname/><email/></author><version>2.0</version></document-info>';
        pageHtml += '<publish-info><book-name>' + BookTitle + '</book-name></publish-info></description>';
        pageHtml += '<body>';
        pageHtml += '<title>';
        pageHtml += '<p>' + BookTitle + '</p>';
        pageHtml += '</title>';

        //var chp = new Array();

        var links = document.getElementsByClassName("taglnk2");
        for (var i = 0; i < links.length; i++) {
            book.childNodes[0].innerHTML = BookTitle + "(" + (i / links.length * 100) + "% загружено...)"
            var item = links[i];

            PartId = item.href.split('/')[5];
            PartTitle = item.text;

            var chp = MyAjax('booktext', '', 'getbook', BookId, PartId + ':0.0.1::0', UserToken, 0);

            pageHtml += '<section><title><p>' + PartTitle + '</p></title>';

            var Z = chp[0].split(/\n/);
            for (var j in Z) {
                pageHtml += '<p>' + DS('', Z[j]).replace('\r', '').replace('\n', '').replace('[ctr][gry]- Конец фрагмента -[/][/]', '') + '</p>\n';
            }

            pageHtml += '</section>';
        };

        pageHtml += '</body></FictionBook>';

        var file = new File([pageHtml], BookTitle + '(' + PartTitle + ').fb2', {
            type: "text/plain;charset=utf-8"
        });
        saveAs(file);
    }

}

function unprotect(text) {
    var pageHtml = null;
    if (document.location.hostname == "zelluloza.ru") {
        var BookId = document.getElementById("gotobook").value;
        var PartId = document.getElementsByClassName("taglnk2")[0].href.split('/')[4];
        var UserToken = GetUserToken();
        var BookTitle = document.getElementsByClassName("booklnk4")[1].childNodes[0].innerHTML;
        var PartTitle = document.getElementsByClassName("taglnk2")[0].text;


        if (document.getElementsByClassName("booklnk4")) {

            var series = "";
            var res = new RegExp('.*Серия: (.*)$', 'm').exec(document.getElementsByClassName('serie')[1].outerText);
            if (res !== null)
                series = res[1];

            pageHtml = '<?xml version="1.0" encoding="utf-8"?><FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink">';
            pageHtml += '<description><title-info><genre/><author><first-name>' + document.getElementsByClassName("txt")[5].text + '</first-name><last-name/></author>';
            pageHtml += '<book-title>' + BookTitle + '</book-title>';
            pageHtml += '<annotation><p>' + document.getElementsByTagName("meta", "")[4].content + '</p></annotation>';
            pageHtml += '<lang>ru</lang><src-lang>ru</src-lang>';
            pageHtml += '<sequence name="' + series + '" number="" />';
            pageHtml += '</title-info><document-info><author><nickname/><email/></author><version>2.0</version></document-info>';
            pageHtml += '<publish-info><book-name>' + BookTitle + '</book-name></publish-info></description>';
            pageHtml += '<body>';
            pageHtml += '<title>';
            pageHtml += '<p>' + BookTitle + '</p>';
            pageHtml += '</title>';
            pageHtml += '<section><title><p>' + PartTitle + '</p></title>';
        }

        var MaxProtection = my_getbyid("protected1").src !== '';
        if (!MaxProtection) {
            var Z = chp[0].split(/\n/);

            for (var j in Z) {
                pageHtml += '<p>' + DS('', Z[j]).replace('\r', '').replace('\n', '').replace('[ctr][gry]- Конец фрагмента -[/][/]', '') + '</p>\n';
            }
            pageHtml += '</section></body></FictionBook>';
            var file = new File([pageHtml], BookTitle + '(' + PartTitle + ').fb2', {
                type: "text/plain;charset=utf-8"
            });
            saveAs(file);
        } else {
            var pages = new Array();
            oCanvas = my_getbyid("cnv1");
            oCtx = oCanvas.getContext("2d");
            var page = 0;
            var loaded = false;
            for (page = 0; page <= maxpg; page += pagessize) {
                pages[page] = "/get/" + base64_encode(bookid + ":" + chapterid + ":" + pagessize + ":" + page);
            }

            var binaryImages = "";
            var pp = new ImagePreloader(pages, function(aImages, nLoaded) {
                aImages.forEach(function(item, i, aImages) {
                    if (item.bLoaded) {
                        oCtx.drawImage(item, 0, 0);
                        pageHtml += '<image xlink:href="#page_' + i + '.jpg"/>\n';
                        binaryImages += '<binary content-type="image/png" id="page_' + i + '.jpg">\n' + oCanvas.toDataURL("image/png", 1.0).replace('data:image/png;base64,', '') + '\n</binary>';
                    }
                });

                pageHtml += '</section></body>';
                pageHtml += binaryImages;
                pageHtml += '</FictionBook>';
                var file = new File([pageHtml], BookTitle + '(' + PartTitle + ').fb2', {
                    type: "text/plain;charset=utf-8"
                });
                saveAs(file);
            });

        }
    }
}

unsafeWindow.wait_for_text = function() {


    var text = document.getElementById("bookpgm");
    if (null === text) {
        var book = document.getElementsByClassName("booklnk4")[1];
        if (null === book)
            alert('No copyable text found!');
        else {
            var button = document.createElement("BUTTON");
            button.innerHTML = 'Get fb2';
            button.addEventListener('click', function() {
                AllBook(book);
            }, true);
            book.parentNode.insertBefore(button, book);
        }
        return;
    }

    if (text.innerHTML.length > 100) {
        var button = document.createElement("BUTTON");
        button.innerHTML = 'Get fb2';
        button.addEventListener('click', function() {
            unprotect(text);
        }, true);
        text.parentNode.insertBefore(button, text);
    } else
        window.setTimeout("wait_for_text()", 1000);
};

window.setTimeout("wait_for_text()", 1000);