Zelluloza Dumper

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

目前为 2016-08-09 提交的版本。查看 最新版本

// ==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);