Zelluloza Dumper

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

目前為 2016-08-09 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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);