[Userscript] YYApp downloader

  Bài viết hay nhất1
Tải truyện từ app.truyenyy.com định dạng txt hoặc html. Sau đó, bạn có thể dùng Mobipocket Creator để tạo ebook prc.

Demo


[You must be registered and logged in to see this image.]
YYApp downloader

Cài đặt


Dùng một trong các link sau:

  1. [You must be registered and logged in to see this link.]
  2. [You must be registered and logged in to see this link.]
  3. [You must be registered and logged in to see this link.]

Mã nguồn


Code:
// ==UserScript==
// @name         YYApp downloader
// @namespace    https://baivong.github.io/
// @description  Tải truyện từ app.truyenyy.com định dạng txt hoặc html. Sau đó, bạn có thể dùng Mobipocket Creator để tạo ebook prc
// @version      1.1.0
// @icon         http://i.imgur.com/3lomxTC.png
// @author       Zzbaivong
// @license      MIT
// @include      /^https?:\/\/app\.truyenyy\.com\/truyen\/[^\/]+\/(danh\-sach\-chuong\/(\?p=\d+)?)?$/
// @require      https://code.jquery.com/jquery-3.2.0.min.js
// @require      https://greasyfork.org/scripts/18532-filesaver/code/FileSaver.js?version=164030
// @noframes
// @connect      self
// @supportURL   https://github.com/baivong/Userscript/issues
// @run-at       document-idle
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function ($, window, document, undefined) {
    'use strict';

    /**
     * Export data to a text file (.txt)
     * @type {Boolean} true  : txt
     *                 false : html
     */
    var textOnly = true;

    /**
     * Enable logging in Console
     * @type {Number} 0 : Disable
     *                1 : Error
     *                2 : Info + Error
     */
    var debugLevel = 0;


    function downloadFail(err) {
        if (!oneChap) {
            $download.css('background', '#f26a65');
            titleError.push(chapTitle);
        }

        if (textOnly) {
            txt += LINE2 + url.toUpperCase() + LINE2;
        } else {
            txt += '<h2 class="title">' + url + '</h2>';
        }

        if (debugLevel == 2) console.log('%cError: ' + url, 'color:red;');
        if (debugLevel > 0) console.error(err);
    }

    function saveEbook() {
        var ebookTitle = oneChap ? chapTitle : $('h1').text().trim(),
            fileName = ebookTitle,
            fileType,
            blob;

        if (endDownload) return;
        endDownload = true;

        if (!oneChap) {
            var ebookAuthor = $('td:contains("Tác giả")').next().find('a').text().trim(),
                $ebookType = $('td:contains("Thể loại")'),
                ebookType = [],

                credits = '<p>Truyện được tải từ <a href="' + location.href + '">TruyenYY</a></p><p>Userscript được viết bởi: <a href="https://baivong.github.io/">Zzbaivong</a></p>',
                creditsTxt = LINE2 + 'Truyện được tải từ ' + location.href + LINE + 'Userscript được viết bởi: Zzbaivong' + LINE2,

                beginEnd = '';

            if ($ebookType.length) {
                $ebookType = $ebookType.next().find('a');
                $ebookType.each(function () {
                    ebookType.push($(this).text().trim());
                });
                ebookType = ebookType.join(', ');

                if (textOnly) {
                    ebookType = LINE + 'Thể loại: ' + ebookType;
                } else {
                    ebookType = '<h3>Thể loại: <font color="green">' + ebookType + '</font></h3>';
                }
            } else {
                ebookType = '';
            }

            if (titleError.length) {
                if (textOnly) {
                    titleError = LINE + 'Các chương lỗi: ' + titleError.join(', ') + LINE;
                } else {
                    titleError = '<h4>Các chương lỗi: <font color="gray">' + titleError.join(', ') + '</font></h4>';
                }

                if (debugLevel > 0) console.warn('Các chương lỗi:', titleError);
            } else {
                titleError = '';
            }

            if (textOnly) {
                if (begin !== end) beginEnd = LINE + 'Từ [' + begin + '] đến [' + end + ']';
                txt = ebookTitle.toUpperCase() + LINE2 + 'Tác giả: ' + ebookAuthor + ebookType + beginEnd + titleError + creditsTxt + txt;
            } else {
                if (begin !== end) beginEnd = '<br><h4>Từ <font color="gray">' + begin + '</font> đến <font color="gray">' + end + '</font></h4>';
                txt = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body><h1><font color="red">' + ebookTitle + '</font></h1><h3>Tác giả: <font color="blue">' + ebookAuthor + '</font></h3>' + ebookType + beginEnd + titleError + '<br><br>' + credits + '<br><br><br>' + txt + '</body></html>';
            }
        }

        if (textOnly) {
            fileName += '.txt';
            fileType = 'text/plain';
        } else {
            fileName += '.html';
            fileType = 'text/html';
        }

        if (oneChap) txt = txt.trim();

        blob = new Blob([txt], {
            encoding: 'UTF-8',
            type: fileType + ';charset=UTF-8'
        });

        if (!oneChap) {
            $download.attr({
                href: window.URL.createObjectURL(blob),
                download: fileName
            }).html('<i class="material-icons">check</i> Tải xong').css('background', '#66bb6a').off('click');

            $win.off('beforeunload');
        }

        document.title = '[⇓] ' + ebookTitle;
        if (debugLevel === 2) console.log('%cDownload Finished!', 'color:blue;');
        if (debugLevel > 0) console.timeEnd('YYApp Downloader');

        saveAs(blob, fileName);
    }

    function getContent() {
        if (endDownload) return;

        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            onload: function (response) {
                var $data = $(response.responseText),
                    $chapter = $data.find('.chap-content'),
                    $next = $data.find('.weui_btn:contains("Tiếp"):last'),
                    nextUrl;

                if (endDownload) return;

                chapTitle = $data.find('.chap-title').text().trim().replace(/^(Chương\s\d+)(\s+?Chương\s?[^\:]+\:)?/, '$1 :');

                if (!$chapter.length) {
                    downloadFail('Missing content.');
                } else {
                    if (!oneChap) $download.css('background', 'orange');

                    if (textOnly) {
                        txt += LINE2 + chapTitle.toUpperCase() + LINE2;
                    } else {
                        txt += '<h2 class="title">' + chapTitle + '</h2>';
                    }

                    $chapter.each(function () {
                        var $this = $(this),
                            $img = $this.find('img');

                        if ($img.length) $img.replaceWith(function () {
                            if (textOnly) {
                                return LINE + this.src + LINE;
                            } else {
                                return '<a href="' + this.src + '">Click để xem ảnh</a>';
                            }
                        });

                        if (textOnly) {
                            $this = $($this.html().replace(/\r?\n+/g, ' '));
                            $this.find('br').replaceWith('\r\n');
                            $this.find('p, div').after('\r\n');
                            txt += $this.text().trim();
                        } else {
                            txt += $this.html();
                        }
                    });

                    if (!oneChap) count++;

                    if (debugLevel === 2) console.log('%cComplete: ' + url, 'color:green;');
                }

                if (!oneChap) {
                    if (count === 1) begin = chapTitle;
                    end = chapTitle;

                    $download.text(chapTitle);
                    document.title = '[' + count + '] ' + pageName;
                }

                if ($next.hasClass('weui_btn_disabled') || oneChap) {
                    saveEbook();
                    return;
                }

                if ($next.length) {
                    nextUrl = $next.attr('href');

                    if (nextUrl === url || nextUrl === '') {
                        saveEbook();
                        return;
                    }
                } else {
                    saveEbook();
                    return;
                }

                url = nextUrl;
                getContent();
            },
            onerror: function (err) {
                downloadFail(err);
                saveEbook();
            }
        });
    }


    var oneChap = false,

        txt = '',
        url = '',

        chapTitle = '',

        LINE = '\r\n\r\n',
        LINE2 = '\r\n\r\n\r\n\r\n',

        endDownload = false;


    if (/^\/truyen\/[^\/]+\/danh\-sach\-chuong\/$/.test(location.pathname)) {
        oneChap = true;

        $('a.weui_cell').on('contextmenu', function (e) {
            e.preventDefault();

            if (debugLevel > 0) console.time('YYApp Downloader');
            if (debugLevel === 2) console.log('%cDownload Start!', 'color:blue;');
            document.title = '[...] Vui lòng chờ trong giây lát';

            url = this.href;
            txt = '';

            getContent();
        });
    } else {
        var pageName = document.title,
            $win = $(window),

            $download = $('<a>', {
                class: 'weui_btn weui_btn_default',
                href: '#download',
                css: {
                    background: '#29b6f6',
                    color: '#ffffff'
                },
                text: 'Tải xuống'
            }),

            count = 0,
            begin = '',
            end = '',

            titleError = [];

        url = $('.weui_btn:contains("Đọc Từ Đầu")').attr('href');


        $('.btns').append($('<div>', {
            class: 'flexbox flex-row"'
        }).append($('<div>', {
            class: 'flexbox-item'
        }).append($download)));

        $download.one('click contextmenu', function (e) {
            e.preventDefault();

            if (e.type === 'contextmenu') {
                var beginUrl = prompt("Nhập URL chương truyện bắt đầu tải:", location.origin + url);
                if (beginUrl !== null && /^https?:\/\/app\.truyenyy\.com\/chuong\/[^\/]+\/$/i.test(beginUrl.trim())) url = beginUrl.replace(location.origin, '');

                $download.off('click');
            } else {
                $download.off('contextmenu');
            }

            if (debugLevel > 0) console.time('YYApp Downloader');
            if (debugLevel === 2) console.log('%cDownload Start!', 'color:blue;');
            document.title = '[...] Vui lòng chờ trong giây lát';

            getContent();

            $win.on('beforeunload', function () {
                return 'Truyện đang được tải xuống...';
            });

            $download.one('click', function (e) {
                e.preventDefault();

                saveEbook();
            });
        });
    }

})(jQuery, window, document);

Hướng dẫn


Tải truyện


Script hoạt động sẽ tạo ra nút Tải xuống tại trang giới thiệu truyện, click vào sẽ tải bộ truyện đó.
Bạn có thể theo dõi quá trình trong Console (F12 > console), nếu chương truyện lỗi sẽ hiện link màu đỏ.

Khi quá trình tải hoàn tất, định dạng file tải xuống là txt. Nếu bạn muốn sử dụng định dạng html, hãy chỉnh tham số textOnly trong mã nguồn thành false.

Chọn chương bắt đầu tải


Click chuột phải trên nút Tải xuống và nhập URL của chương cần bắt đầu vào khung nhập liệu, tiến trình sẽ bắt đầu từ chương đó đến cuối danh sách.

Tải từng chương riêng biệt


Nhấn vào nút Danh Sách Chương và Click chuột phải trên liên kết chương cần tải trong danh mục.

Dừng và tải xuống


Khi gặp lỗi trong quá trình tải mà không thể tiếp tục, tiến trình sẽ tự dừng và tải truyện.
Bạn có thể dừng và tải truyện ngay lập tức bằng cách click vào nút Tải xuống khi tiến trình đang chạy.

Đọc truyện


Với định dạng txt, bạn có thể đọc trực tiếp bằng các Ebook Reader phổ biến trên thiết bị của bạn. Ví dụ:


  • Windows: MobiPocket Reader.
  • Linux: FBReader.
  • Windows Phone: MoHoo Reader. Thiết lập Setting >> Reading > Scroll free : On để tránh lỗi ngắt chữ.
  • Android: AlReader.


Định dạng html thường không được hỗ trợ đọc trực tiếp hoặc có nhiều hạn chế, bạn nên chuyển sang dạng prc theo hướng dẫn dưới đây.

Tạo ebook prc


Tải phần mềm Mobipocket Creator. Khi cài đặt, nên chọn phiên bản Creator Home Edition.

Sau khi cài đặt hoàn tất, chạy Mobipocket Creator, trong mục Import From Exiting File, nhấp vào HTML document.

Tại trang Import from HTML document:

  1. Choose a file: Nhấn Browse..., chọn file truyện bạn vừa tải trước đó.
  2. Create publication in folder: Đây là vị trí chứa ebook sau khi tạo, nên để mặc định.
  3. Language: Chọn Vietnamese.
  4. Encoding: Chọn UTF-8.

Nhấn nút Import.

Sau khi import thành công, bạn sẽ được chuyển đến trang cấu hình cho Ebook.

Mục Conver Image là nơi bạn chèn ảnh bìa cho Ebook. Nhấn nút Add a Conver image và chọn ảnh bạn muốn làm bìa rồi nhấn nút Update.

Để tạo mục lục cho các chương truyện, chọn mục Table of contents, nhấn nút Add a Table of contents.
Ở phần Table of Contents Title, bạn điền: Mục lục vào ô nhập liệu.
Phần Table of Contents Generation rules, bạn điền vào 3 ô trên dòng First level lần lượt là:

  • Tagname: h2
  • Attribute: class
  • Value: title

Nhấn nút Update.

Đến đây bạn đã hoàn thành những việc cần thiết để tạo Ebook, Nhấn menu Build ở phía trên, sau đó chọn nút Build ở trang hiện ra để tạo Ebook định dạng prc. File này sẽ được lưu ở thư mục bạn chọn ở Create publication in folder. Trong thư mục này còn chứa một số file cấu hình khác, bạn có thể xóa chúng đi.
Tags: [You must be registered and logged in to see this link.]
  Bài viết hay nhất2
Cái này nó đổi trở lại "truyenyy.com" rồi Ad ơi.
  Bài viết hay nhất3
Nó cũng cập nhật giao diện mới luôn rồi. Mình sẽ làm một script tổng hợp sau, giờ chưa sắp xếp được thời gian.
Dù sao mớ truyện mình tải về trước đây còn chưa đọc được một nửa :p
  Bài viết hay nhất4
Hình như giao diện cũ nó dùng cho Mobile. Mình dùng chuyển sang Mobile mode cho Chrome rồi chỉnh lại link thì cũng thấy được như cái giao diện đó nhưng nhấn vào thì chỉ ra vài dòng tròng cái html ra
You cannot reply to topics in this forum