Đăng Nhanh

Đăng truyện nhanh TTV với nhiều tính năng mới và tự động tách chương

当前为 2025-03-06 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Đăng Nhanh
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Đăng truyện nhanh TTV với nhiều tính năng mới và tự động tách chương
// @author       HA
// @match        https://tangthuvien.net/dang-chuong/story/*
// @match        https://tangthuvien.net/danh-sach-chuong/story/*
// @grant        none
// @required     https://code.jquery.com/jquery-3.2.1.min.js
// @icon         https://tangthuvien.net/images/icon-favico.png
// @copyright 2021-2023, by HA
// @license AGPL-3.0-only
// @collaborator HA
// ==/UserScript==

var headerSign = "";
var footerSign = "";
var dăngnhanhTTV =  {
    YEAR_ALIVE: 2021,
    MAX_CHAPTER_POST: 10,
    CHAP_NUMBER: 1,
    CHAP_STT: 1,
    CHAP_SERIAL: 1,
    CHAP_NUMBER_ORIGINAL: 1,
    CHAP_STT_ORIGINAL: 1,
    CHAP_SERIAL_ORIGINAL: 1,
    addNewChapter: function () {
        var me = this;
        if ((me.CHAP_NUMBER + 1) <= me.MAX_CHAPTER_POST) {
            me.updateChapNumber(true);
            var chap_vol = parseInt(jQuery('.chap_vol').val());
            var chap_vol_name = jQuery('.chap_vol_name').val();
            var html =
                '<div data-gen="MK_GEN" id="COUNT_CHAP_' + me.CHAP_NUMBER + '_MK">' +
                '<div class="col-xs-12 form-group"></div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="chap_stt">STT</label>' +
                '<div class="col-sm-8">' +
                '<input class="form-control" required name="chap_stt[' + me.CHAP_NUMBER + ']" value="' + me.CHAP_STT +
                '" placeholder="Số thứ tự của chương" type="text"/>' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="chap_number">Chương thứ..</label>' +
                '<div class="col-sm-8">' +
                '<input value="' + me.CHAP_SERIAL + '" required class="form-control" name="chap_number[' + me.CHAP_NUMBER +
                ']" placeholder="Chương thứ.. (1,2,3..)" type="text"/>' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="chap_name">Quyển số</label>' +
                '<div class="col-sm-8">' +
                '<input class="form-control" name="vol[' + me.CHAP_NUMBER +
                ']" placeholder="Quyển số" type="number" value="' + chap_vol + '" required/>' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="chap_name">Tên quyển</label>' +
                '<div class="col-sm-8">' +
                '<input class="form-control chap_vol_name" name="vol_name[' + me.CHAP_NUMBER +
                ']" placeholder="Tên quyển" type="text" value="' + chap_vol_name + '" />' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="chap_name">Tên chương</label>' +
                '<div class="col-sm-8">' +
                '<input required class="form-control" name="chap_name[' + me.CHAP_NUMBER +
                ']" placeholder="Tên chương" type="text"/>' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="introduce">Nội dung</label>' +
                '<div class="col-sm-8">' +
                '<textarea maxlength="75000" style="color:#000;font-weight: 400;" required class="form-control" ' +
                'name="introduce[' + me.CHAP_NUMBER + ']" rows="20" placeholder="Nội dung" type="text"></textarea>' +
                '</div>' +
                '</div>' +
                '<div class="form-group">' +
                '<label class="col-sm-2" for="adv">Quảng cáo</label>' +
                '<div class="col-sm-8">' +
                '<textarea maxlength="1000" class="form-control" name="adv[' + me.CHAP_NUMBER +
                ']" placeholder="Quảng cáo" type="text"></textarea>' +
                '</div>' +
                '</div>' +
                '</div>';
            jQuery('#add-chap').before(html);
        }
        else {
            var chapterLeft = me.MAX_CHAPTER_POST - me.CHAP_NUMBER;
            chapterLeft = chapterLeft < 0 ? 0 : chapterLeft;
            alert('Bạn nên đăng tối đa ' + me.MAX_CHAPTER_POST + ' chương một lần, số chương đã tạo ' +
                me.CHAP_NUMBER + ' chương, bạn có thể đăng thêm ' + chapterLeft + ' chương nữa.');
        }
    },
    createListAddChapter: function (isSilent) {
        var me = this;
        var chapterAdd = 0;
        chapterAdd = parseInt(jQuery("#qpNumberOfChapter").val());
        if ((me.CHAP_NUMBER + chapterAdd) <= me.MAX_CHAPTER_POST) {
            for (var i = 0; i < chapterAdd; i++) {
                me.addNewChapter();
            }
            if (!isSilent) {
                alert('Đã tạo thêm ' + chapterAdd + ' chương, hãy copy và dán nội dung cần đăng.');
            }
        }
        else {
            alert('Bạn nên đăng tối đa ' + me.MAX_CHAPTER_POST + ' chương một lần, số chương đã tạo ' + me.CHAP_NUMBER + ' chương, bạn có thể đăng thêm ' + (me.MAX_CHAPTER_POST - me.CHAP_NUMBER) + ' chương nữa.');
        }
    },
    removeLastedPost: function () {
        var me = this;
        jQuery("#COUNT_CHAP_" + me.CHAP_NUMBER + "_MK").remove();
        me.updateChapNumber();
    },
    updateChapNumber: function (isAdd) {
        var me = this;
        try {
            if (isAdd) {
                var chap_stt = parseInt(jQuery('.chap_stt1').val());
                var chap_serial = parseInt(jQuery('.chap_serial').val());
                if (parseInt(jQuery('#chap_stt').val()) > chap_stt) {
                    chap_stt = parseInt(jQuery('#chap_stt').val());
                }
                if (parseInt(jQuery('#chap_serial').val()) > chap_serial) {
                    chap_serial = parseInt(jQuery('#chap_serial').val());
                }
                me.CHAP_STT = chap_stt;
                me.CHAP_SERIAL = chap_serial;
                me.CHAP_NUMBER++;
                me.CHAP_STT++;
                me.CHAP_SERIAL++;
            }
            else {
                if (me.CHAP_NUMBER > me.CHAP_NUMBER_ORIGINAL) {
                    me.CHAP_NUMBER--;
                }
                if (me.CHAP_STT > me.CHAP_STT_ORIGINAL) {
                    me.CHAP_STT--;
                }
                if (me.CHAP_SERIAL > me.CHAP_SERIAL_ORIGINAL) {
                    me.CHAP_SERIAL--;
                }
            }
            jQuery('#chap_number').val(me.CHAP_NUMBER);
            jQuery('#chap_stt').val(me.CHAP_STT);
            jQuery('#chap_serial').val(me.CHAP_SERIAL);
            jQuery('#countNumberPost').text(me.CHAP_NUMBER);
        }
        catch (e) {
            console.log("Lỗi: " + e);
        }
    },
    createEl: function (n) {
        return document.createElement(n);
    },
    addStyle: function (style) {
        var me = this;
        var s = me.createEl("style"),
            h = document.getElementById('HA');
        s.type = "text/css";
        s.appendChild(document.createTextNode(style));
        h.appendChild(s);
    },
    addCss: function () {
        var me = this;
        var s =
            '#HA { ' +
            'background-color: rgb(255, 255, 255) !important;' +
            'padding: 3px 15px;' +
            'color: black !important;' +
            'border-radius: 5px 0px 0px 5px;' +
            'margin-bottom: 15px;' +
            'position: fixed;' +
            'right: 10px;' +
            'top: 10px;' +
            'max-width: 400px;' +
            'z-index: 9999;' +
            'box-shadow: -2px 0 5px rgba(0,0,0,0.1);' +
            '}' +
            '#HA > .form-group > div {' +
            'font-size: 13px;' +
            'color: black !important;' +
            '}' +
            '#HA > p {' +
            'font-size: 13px;' +
            'color: black !important;' +
            'text-align: right;' +
            '}' +
            '#HA .HA-option {' +
            'padding: 5px;' +
            'border: 1px dashed #4CAF50;' +
            'border-radius: 5px;' +
            'margin-bottom: 32px;' +
            '}' +
            '#HA .HA-option-label {' +
            'width: 100%;' +
            'background-color: black;' +
            'padding: 10px;' +
            'border-radius: 5px 5px 0px 0px;' +
            'margin: 0;' +
            '}' +
            '#qpn {' +
            'max-height: 300px;' +
            'overflow-y: auto;' +
            'margin-top: 10px;' +
            'font-size: 12px;' +
            '}' +
            '#qpn div {' +
            'font-size: 12px;' +
            'margin: 2px 0;' +
            '}' +
            '.hidden-element, .hidden-config-section {' +
            'display: none !important;' +
            'height: 0 !important;' +
            'overflow: hidden !important;' +
            'visibility: hidden !important;' +
            'padding: 0 !important;' +
            'margin: 0 !important;' +
            'position: absolute !important;' +
            'left: -9999px !important;' +
            '}';
        me.addStyle(s);
        setTimeout(function () {
            const elementsToHide = [
                document.querySelector('.hidden-config-section'),
                document.getElementById('qpSplitValue'),
                document.getElementById('qpSplitValueReplace'),
                document.getElementById('qpNumberOfChapter')
            ];
            elementsToHide.forEach(function (el) {
                if (el) {
                    el.style.display = 'none';
                    el.style.visibility = 'hidden';
                    el.style.height = '0px';
                    el.style.overflow = 'hidden';
                    el.style.position = 'absolute';
                    el.style.left = '-9999px';
                    el.setAttribute('aria-hidden', 'true');
                }
            });
        }, 100);
    },
    createInjectHTML: function () {
        var me = this;
        var h =
            '<div id="HA">' +
            '<div class="form-group"></div>' +
            '<center>' +
            '<h3>CÔNG CỤ ĐĂNG NHANH</h3>' +
            '</center>' +
            '<center>' +
            '<h4><span id="short-chapter-warning" style="display:none; color:red;"></span></h4>' +
            '</center>' +
            '<div class="form-group">' +
            '<textarea placeholder="Nội dung truyện (Dán vào đây để tự động tách chương)" id="qpContent" class="form-control" rows="5"></textarea>' +
            '<div class="form-group" id="qpAdv" class="form-control" rows="2"></div>' +
            '<div class="form-group" style="text-align: center; margin-top: 10px;">' +
            '<button type="button" id="qpButtonSubmit" class="btn btn-default" style="margin: 0 auto;" onclick="javascript:;">Đăng chương</button>' +
            '<input type="button" id="qpButtonRemoveEmpty" value="Xóa chương trống" class="btn btn-danger" style="display:none;" />' +

            '</div>' +
            '<div class="form-group">' +
            '<span id="qpn" style="margin:0px 15px;font-weight:bold"></span>' +
            '</div>' +
            '</div>' +
            '<div class="hidden-config-section" style="display:none;height:0;overflow:hidden;visibility:hidden;">' +
            '<h4></h4>' +
            '<div class="form-group">' +
            '<input type="text" id="qpSplitValue" class="form-control" value="/[c|C]hương\\s?\\d+\\s?:?\\s?/">' +
            '</div>' +
            '<div class="form-group" id="qpSplitValueReplace"></div>' +
            '<div class="form-group">' +
            '<input type="number" placeholder="Thêm" value="9" id="qpNumberOfChapter" class="form-control">' +
            '</div>' +
            '</div>' +
            '<div class="form-group">' +
            '<b><center>' +
            '</center></b>' +
            '</div>' +
            '</div>';
        jQuery(".list-in-user").before(h);
    },
    performAction: function () {
        try {
            var me = this;
            var a = jQuery("#qpContent").val(),
                s = jQuery("#qpSplitValue").val(),
                st = jQuery('#qpSplitValueReplace').val().trim(),
                titles = jQuery("[name^=chap_name]"),
                contents = jQuery("[name^=introduce]"),
                advs = jQuery("[name^=adv]"),
                error = false,
                advContent = jQuery("#qpAdv").val();
            me.fillEmptyForms(titles, contents, advs, advContent, st);
            if (s.startsWith('/') && s.endsWith('/') && s.length > 0) {
                s = new RegExp(s.substring(1, s.length - 1));
            }
            a = a.split(s).filter(function (entry) {
                return entry.trim() !== "";
            });
            if (!loop && a.length < titles.length) {
                error = true;
            }
            if (loop && (a.length / 2) < titles.length) {
                error = true;
            }
            var splitTitle = st.toLowerCase();
            if (!loop) {
                jQuery.each(titles, (function (k, v) {
                    if (k < a.length) {
                        var at = a[k].trim(),
                            content = at.split('\n'),
                            originalTitle = content.shift().trim(),
                            title = originalTitle.toLowerCase();
                        originalTitle = me.ucFirst(originalTitle);
                        if (title.startsWith(splitTitle)) {
                            titles[k].value = originalTitle;
                            contents[k].value = headerSign + "\r\n" + content.join('\n') + "\r\n" + footerSign;
                            advs[k].value = advContent;
                        }
                        else {
                            titles[k].value = st + " " + originalTitle;
                            contents[k].value = headerSign + "\r\n" + content.join('\n') + "\r\n" + footerSign;
                            advs[k].value = advContent;
                        }
                    }
                    else {
                        jQuery("#qpContent").val("Đã thực hiện được " + k + " /" + (titles.length) + " nhập ban đầu, có thể nhấn Xóa chương trống, sau đó nhấn Đăng chương");
                        return false;
                    }
                }));
            }
            else {
                var j = 0,
                    ha = a.length / 2;
                jQuery.each(titles, (function (k, v) {
                    if (k < ha) {
                        var at = a[++j].trim(),
                            content = at.split('\n'),
                            originalTitle = content.shift().trim(),
                            title = '';
                        title = originalTitle.toLowerCase();
                        if (title === '') {
                            while (title === '' && content.length > 0) {
                                originalTitle = content.shift().trim();
                                title = originalTitle.toLowerCase();
                            }
                        }
                        originalTitle = me.ucFirst(originalTitle);
                        if (title.startsWith(splitTitle)) {
                            titles[k].value = originalTitle;
                            contents[k].value = headerSign + "\r\n" + content.join('\n') + "\r\n" + footerSign;
                            advs[k].value = advContent;
                        }
                        else {
                            titles[k].value = st + " " + originalTitle;
                            contents[k].value = headerSign + "\r\n" + content.join('\n') + "\r\n" + footerSign;
                            advs[k].value = advContent;
                        }
                    }
                    else {
                        jQuery("#qpContent").val("Đã thực hiện được " + k + " /" + (titles.length) + " nhập ban đầu, có thể nhấn Vẫn Đăng để tiếp tục");
                        return false;
                    }
                    j++;
                }));
            }
            if (!error) {
                jQuery("#qpButtonSubmit").removeClass("btn-disable").addClass("btn-success");
                jQuery("#qpContent").val("Đã thực hiện xong, OK");
            }
        }
        catch (e) {
            console.log("Lỗi: " + e);
        }
    },
    removeEmptyList: function () {
        try {
            var me = this;
            var titles = jQuery("[name^=chap_name]"),
                contents = jQuery("[name^=introduce]"),
                count = 0;
            jQuery("#qpn").html('');
            if (titles && titles.length) {
                for (var i = 0; i < titles.length; i++) {
                    var t = titles[i];
                    var c = contents[i];
                    if (t) {
                        if (!t.value || (c && !c.value.trim().replace(headerSign, '').replace(footerSign, '').trim())) {
                            if (t.parentElement.parentElement.parentElement.tagName != 'FORM') {
                                t.parentElement.parentElement.parentElement.remove();
                            }
                            me.updateChapNumber();
                            count++;
                        }
                    }
                }
            }
            alert('Đã loại bỏ ' + count + ' chương trống. Đã có thể nhấn Đăng chương');
            me.checkEmptyForms(); // Kiểm tra lại sau khi xóa
        }
        catch (e) {
            console.log("Lỗi: " + e);
        }
    },
    registerEvents: function () {
        var me = this;
        jQuery("#qpContent").on("paste", function (e) {
            jQuery(this).val("");
            var processingMsg = jQuery("<div>", {
                id: "processing-notification",
                text: "Đang xử lý tách chương...",
                css: {
                    position: "fixed",
                    top: "50%",
                    left: "50%",
                    transform: "translate(-50%, -50%)",
                    backgroundColor: "rgba(0, 0, 0, 0.7)",
                    color: "white",
                    padding: "15px 20px",
                    borderRadius: "5px",
                    zIndex: "10000",
                    fontSize: "16px"
                }
            });
            jQuery("body").append(processingMsg);
            setTimeout(function () {
                dăngnhanhTTV.splitChapters();
                jQuery("#processing-notification").fadeOut(300, function () {
                    jQuery(this).remove();
                });
                me.checkEmptyForms();
                var completeMsg = jQuery("<div>", {
                    id: "complete-notification",
                    text: "Đã tách chương tự động!",
                    css: {
                        position: "fixed",
                        top: "20px",
                        right: "20px",
                        backgroundColor: "#4CAF50",
                        color: "white",
                        padding: "10px 15px",
                        borderRadius: "5px",
                        zIndex: "10000",
                        fontSize: "14px"
                    }
                });
                jQuery("body").append(completeMsg);
                completeMsg.fadeIn(300).delay(2000).fadeOut(500, function () {
                    jQuery(this).remove();
                });
            }, 500);
        });
        jQuery("#qpButtonRemoveLast").on('click', function (e) {
            e.preventDefault();
            dăngnhanhTTV.removeLastedPost();
        });
        jQuery("#qpButtonGenChapter").on('click', function (e) {
            e.preventDefault();
            dăngnhanhTTV.createListAddChapter();
        });
        me.readCookies();
    },
    readCookies: function () {
        try {
            var cookieValue = null;
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = cookies[i].trim();
                if (cookie.indexOf('HAconfig=') === 0) {
                    cookieValue = decodeURIComponent(cookie.substring('HAconfig='.length));
                    break;
                }
            }
            if (cookieValue) {
                try {
                    var settings = JSON.parse(cookieValue);
                    if (settings.splitValue) jQuery("#qpSplitValue").val(settings.splitValue);
                    if (settings.optionLoop !== undefined) jQuery("#qpOptionLoop")[0].checked = settings.optionLoop;
                    if (settings.numberChapter) jQuery("#qpNumberOfChapter").val(settings.numberChapter);
                    if (settings.splitValueReplace) jQuery("#qpSplitValueReplace").val(settings.splitValueReplace);
                } catch (e) {
                    console.log("Lỗi khi parse cookie: " + e);
                }
            }
        } catch (e) {
            console.log("Lỗi khi đọc cookie: " + e);
        }
    },
    setCopyRight: function () {
        try {
            var me = this;
            var str = "© " + me.YEAR_ALIVE;
            var d = new Date(),
                y = d.getFullYear();
            if (y > me.YEAR_ALIVE) {
                str += " - " + y;
            }
            jQuery('#mkcopyright').text(str);
        }
        catch (e) {
            console.log("Lỗi: " + e);
        }
    },
    replaceTitle: function () {
        var me = this,
            titles = jQuery("[name^=chap_name]"),
            replaceVal = jQuery("#qpTextTitleReplace").val(),
            findVal = jQuery("#qpTextTitleFind").val();
        if (findVal.startsWith('/') && findVal.endsWith('/') && findVal.length > 2) {
            var re = findVal.substring(1, findVal.length - 1);
            findVal = new RegExp(re);
        }
        if (titles && titles.length > 0) {
            for (var i = 0; i < titles.length; i++) {
                var t = titles[i];
                if (t && t.value) {
                    t.value = t.value.replace(findVal, replaceVal);
                }
            }
            alert('Đã thay thế xong.');
        }
    },
    ucFirst: function (str) {
        if (str && typeof str === 'string' && str.length > 0) {
            let fst = str[0].toUpperCase();
            str = str.length === 1 ? fst : fst + str.substring(1);
        }
        return str;
    },
    init: function () {
        try {
            var me = this;
            var chap_number = parseInt(jQuery('#chap_number').val());
            var chap_stt = parseInt(jQuery('.chap_stt1').val());
            var chap_serial = parseInt(jQuery('.chap_serial').val());
            if (parseInt(jQuery('#chap_stt').val()) > chap_stt) {
                chap_stt = parseInt(jQuery('#chap_stt').val());
            }
            if (parseInt(jQuery('#chap_serial').val()) > chap_serial) {
                chap_serial = parseInt(jQuery('#chap_serial').val());
            }
            me.CHAP_NUMBER = me.CHAP_NUMBER_ORIGINAL = chap_number;
            me.CHAP_STT = me.CHAP_STT_ORIGINAL = chap_stt;
            me.CHAP_SERIAL = me.CHAP_STT_ORIGINAL = chap_serial;
            me.createInjectHTML();
            me.addCss();
            me.registerEvents();
            me.setCopyRight();
            me.createListAddChapter(true);
            jQuery('#qpNumberOfChapter').attr('max', me.MAX_CHAPTER_POST);
            jQuery("#qpContent").focus();
            var style = document.createElement('style');
            style.innerHTML = `
                @keyframes blink-red {
                    0% { box-shadow: 0 0 5px rgba(255, 0, 0, 0.5); }
                    50% { box-shadow: 0 0 15px rgba(255, 0, 0, 0.8); }
                    100% { box-shadow: 0 0 5px rgba(255, 0, 0, 0.5); }
                }
                textarea[style*='border: 3px solid red'] {
                    animation: blink-red 2s infinite;
                }
                #short-chapter-warning {
                    animation: blink-red 2s infinite;
                }
            `;
            document.head.appendChild(style);
        }
        catch (e) {
            console.log("Lỗi: " + e);
        }
    },
    copyToClipboard: function (text) {
        var textarea = document.createElement('textarea');
        textarea.value = text;
        textarea.setAttribute('readonly', '');
        textarea.style.position = 'absolute';
        textarea.style.left = '-9999px';
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
    },
    fillEmptyForms: function (titles, contents, advs, advContent, st) {
        var me = this;
        try {
            var maxIterations = 3;
            var iteration = 0;
            var hasEmptyForms = true;
            while (hasEmptyForms && iteration < maxIterations) {
                hasEmptyForms = false;
                for (var i = 0; i < titles.length; i++) {
                    var currentTitle = titles[i];
                    var currentContent = contents[i];
                    if (currentTitle && (!currentTitle.value || (currentContent && !currentContent.value.trim().replace(headerSign, '').replace(footerSign, '').trim()))) {
                        hasEmptyForms = true;
                        var foundNextValid = false;
                        for (var j = i + 1; j < titles.length; j++) {
                            var nextTitle = titles[j];
                            var nextContent = contents[j];
                            if (nextTitle && nextTitle.value && nextContent && nextContent.value.trim().replace(headerSign, '').replace(footerSign, '').trim()) {
                                currentTitle.value = nextTitle.value;
                                currentContent.value = nextContent.value;
                                if (advs && advs[i]) {
                                    advs[i].value = advs[j] ? advs[j].value : advContent;
                                }
                                nextTitle.value = "";
                                nextContent.value = "";
                                if (advs && advs[j]) {
                                    advs[j].value = "";
                                }
                                foundNextValid = true;
                                break;
                            }
                        }
                    }
                }
                iteration++;
            }
            var emptyFormCount = 0;
            for (var i = 0; i < titles.length; i++) {
                var currentTitle = titles[i];
                var currentContent = contents[i];
                if (currentTitle && (!currentTitle.value || (currentContent && !currentContent.value.trim().replace(headerSign, '').replace(footerSign, '').trim()))) {
                    emptyFormCount++;
                }
            }
        } catch (e) {
            console.log("Lỗi khi đẩy chương lên form trống: " + e);
        }
    },
    checkEmptyForms: function() {
        var titles = jQuery("[name^=chap_name]");
        var contents = jQuery("[name^=introduce]");
        var hasEmptyForms = false;
        
        if (titles && titles.length) {
            for (var i = 0; i < titles.length; i++) {
                var t = titles[i];
                var c = contents[i];
                if (t && (!t.value || (c && !c.value.trim().replace(headerSign, '').replace(footerSign, '').trim()))) {
                    if (t.parentElement.parentElement.parentElement.tagName != 'FORM') {
                        hasEmptyForms = true;
                        break;
                    }
                }
            }
        }
        
        if (hasEmptyForms) {
            jQuery("#qpButtonRemoveEmpty").show();
        } else {
            jQuery("#qpButtonRemoveEmpty").hide();
        }
        
        return hasEmptyForms;
    },
    
    splitChapters: function () {
        var me = this;
        try {
            window.shortChapterNotified = false;
            var warningEl = document.getElementById('short-chapter-warning');
            if (warningEl) {
                warningEl.style.display = 'none';
            }
            var content = jQuery("#qpContent").val(),
                st = jQuery('#qpSplitValueReplace').val().trim(),
                advContent = jQuery("#qpAdv").val();
            var lines = content.split('\n');
            var chapters = [];
            var currentChapter = [];
            var regex = /^\s+[Cc]hương\s*\d+:/;
            for (var i = 0; i < lines.length; i++) {
                var line = lines[i];
                if (line.match(regex)) {
                    if (currentChapter.length > 0) {
                        chapters.push(currentChapter.join('\n'));
                        currentChapter = [];
                    }
                    currentChapter.push(line);
                } else {
                    currentChapter.push(line);
                }
            }
            if (currentChapter.length > 0) {
                chapters.push(currentChapter.join('\n'));
            }
            chapters = chapters.filter(function (chapter) {
                var lines = chapter.split('\n');
                return lines.some(function (line, index) {
                    return index > 0 && line.trim().length > 0;
                });
            });
            var i = 0;
            while (i < chapters.length) {
                if (chapters[i].length > 19000) {
                    var largeChapter = chapters[i];
                    var lines = largeChapter.split('\n');
                    var chapterTitle = lines.shift();
                    var contentToSplit = lines.join('\n');
                    var contentLength = contentToSplit.length;
                    var numSubChapters = Math.ceil(contentLength / 15000);
                    var chunkSize = Math.floor(contentLength / numSubChapters);
                    var subChapters = [];
                    var startPos = 0;
                    for (var j = 0; j < numSubChapters; j++) {
                        var endPos = (j === numSubChapters - 1) ? contentLength : startPos + chunkSize;
                        if (j < numSubChapters - 1) {
                            var lookAhead = Math.min(200, contentLength - endPos);
                            var segment = contentToSplit.substring(endPos, endPos + lookAhead);
                            var sentenceEnd = segment.search(/[.!?][^.!?]*$/);
                            if (sentenceEnd !== -1) {
                                endPos += sentenceEnd + 1;
                            }
                        }
                        var subContent = contentToSplit.substring(startPos, endPos);
                        var subTitle = chapterTitle.trim() + " (Phần " + (j + 1) + "/" + numSubChapters + ")";
                        subChapters.push(subTitle + "\n" + subContent);
                        startPos = endPos;
                    }
                    chapters.splice(i, 1, ...subChapters);
                    i += numSubChapters;
                } else {
                    i++;
                }
            }
            var titles = jQuery("[name^=chap_name]");
            var contents = jQuery("[name^=introduce]");
            var advs = jQuery("[name^=adv]");
            var validChapters = 0;
            var processedChapters = 0;
            for (var i = 0; i < Math.min(chapters.length, titles.length); i++) {
                var chapterLines = chapters[i].split('\n');
                var title = chapterLines.shift().trim();
                var content = chapterLines.join('\n');
                if (content) {
                    validChapters++;
                    if (title.includes(':')) {
                        title = title.split(':').slice(1).join(':').trim();
                    }
                    title = me.ucFirst(title);
                    if (title.toLowerCase().startsWith(st.toLowerCase())) {
                        titles[i].value = title;
                    } else {
                        titles[i].value = st + " " + title;
                    }
                    contents[i].value = headerSign + "\r\n" + content + "\r\n" + footerSign;
                    advs[i].value = advContent;
                    var contentWithoutEmpty = content.split('\n')
                        .filter(line => line.trim().length > 0)
                        .join('\n');
                    var charCount = contentWithoutEmpty.length;
                    if (charCount < 3000) {
                        contents[i].style.border = '3px solid red';
                        contents[i].style.borderRadius = '5px';
                        contents[i].style.backgroundColor = 'rgba(255, 0, 0, 0.1)';
                        if (!window.shortChapterNotified) {
                            window.shortChapterNotified = true;
                            var numbershortChapters = document.querySelectorAll("textarea[style*='border: 3px solid red']").length;
                            var warningEl = document.getElementById('short-chapter-warning');
                            if (warningEl) {
                                warningEl.textContent = '⚠️ Có chương dưới 3000 ký tự. ⚠️';
                                warningEl.style.display = 'block';
                            }
                            setTimeout(function () {
                                alert('Cảnh báo: Phát hiện có chương dưới 3000 ký tự.');
                            }, 500);
                        }
                    }
                    processedChapters++;
                }
            }
            var totalProcessedChapters = chapters.length;
            var splitChaptersCount = 0;
            for (var i = 0; i < chapters.length; i++) {
                var firstLine = chapters[i].split('\n')[0];
                if (firstLine && firstLine.includes(" (Phần ")) {
                    splitChaptersCount++;
                }
            }
            var originalChapterCount = totalProcessedChapters - splitChaptersCount + Math.ceil(splitChaptersCount / 2);
            var largeChapters = [];
            for (var i = 0; i < chapters.length; i++) {
                if (chapters[i].length > 19000) {
                    largeChapters.push(i);
                }
            }
            var newChaptersFromSplit = splitChaptersCount;
            var mainSummary = "";
            mainSummary += "Đã xử lý " + totalProcessedChapters + " chương\n";
            mainSummary += "Đã lấy " + Math.min(chapters.length, titles.length) + " chương";
            if (chapters.length > titles.length) {
                mainSummary += "\nĐã lưu " + (chapters.length - titles.length) + " chương vào Clipboard";
            }
            var detailedSummary = "\n";
            detailedSummary += "Đã xử lý " + totalProcessedChapters + " chương\n";
            detailedSummary += "Đã lấy " + Math.min(chapters.length, titles.length) + " chương\n";
            if (chapters.length > titles.length) {
                detailedSummary += "Đã lưu " + (chapters.length - titles.length) + " chương vào Clipboard\n";
            }
            var splitChapterGroups = [];
            var totalSplitParts = 0;
            for (var i = 0; i < chapters.length; i++) {
                var firstLine = chapters[i].split('\n')[0];
                if (firstLine && firstLine.includes(" (Phần ")) {
                    var parts = firstLine.match(/\(Phần (\d+)\/(\d+)\)/);
                    if (parts && parts[1] && parts[2]) {
                        var partNum = parseInt(parts[1]);
                        var totalPartNum = parseInt(parts[2]);
                        var chapterBaseName = firstLine.replace(/\s*\(Phần \d+\/\d+\)/, "").trim();
                        var chapterId = chapterBaseName + "_" + totalPartNum;
                        if (partNum === 1) {
                            splitChapterGroups.push({
                                id: chapterId,
                                name: chapterBaseName,
                                totalParts: totalPartNum
                            });
                        }
                        totalSplitParts++;
                    }
                }
            }
            var largeChapterCount = splitChapterGroups.length;
            var totalParts = totalSplitParts;
            if (largeChapterCount > 0) {
                var mainMsg = "Có " + largeChapterCount + " chương dài được chia thành " + totalParts + " chương\n";
                detailedSummary += mainMsg;
                if (splitChapterGroups.length > 0) {
                    for (var i = 0; i < splitChapterGroups.length; i++) {
                        var chapterMatch = splitChapterGroups[i].name.match(/[Cc]hương\s*(\d+):/);
                        var chapterNum = chapterMatch ? chapterMatch[0] : "Chương";
                        detailedSummary += " - " + chapterNum + " chia thành " + 
                                          splitChapterGroups[i].totalParts + " chương\n";
                    }
                }
            }
            if (largeChapters.length > 0) {
                var largeChaptersProcessed = 0;
                var newChaptersGenerated = 0;
                for (var i = 0; i < chapters.length; i++) {
                    var firstLine = chapters[i].split('\n')[0];
                    if (firstLine && firstLine.includes(" (Phần ")) {
                        var parts = firstLine.match(/\(Phần (\d+)\/(\d+)\)/);
                        if (parts && parts[1] && parts[2]) {
                            if (parts[1] === "1") {
                                largeChaptersProcessed++;
                                newChaptersGenerated += parseInt(parts[2]);
                            }
                        }
                    }
                }
                var mainMsg = "Có " + largeChaptersProcessed + " chương dài được chia thành " + newChaptersFromSplit + " chương\n";
                detailedSummary += mainMsg;
            }
            var titleCounts = {};
            var duplicateTitles = [];
            for (var i = 0; i < titles.length; i++) {
                var title = titles[i].value;
                if (title) {
                    if (titleCounts[title]) {
                        titleCounts[title]++;
                        if (titleCounts[title] === 2) {
                            duplicateTitles.push(title);
                        }
                    } else {
                        titleCounts[title] = 1;
                    }
                }
            }
            if (duplicateTitles.length > 0) {
                detailedSummary += "Có " + duplicateTitles.length + " chương tiêu đề bị lặp lại\n";
                for (var i = 0; i < duplicateTitles.length; i++) {
                    detailedSummary += " - " + duplicateTitles[i] + "\n";
                }
            }
            var shortChapters = [];
            for (var i = 0; i < Math.min(chapters.length, titles.length); i++) {
                var content = contents[i].value.trim().replace(headerSign, '').replace(footerSign, '');
                var charCount = content.length;
                if (charCount < 3000) {
                    var chapterMatch = titles[i].value.match(/[Cc]hương\s*(\d+)/);
                    var chapterNum = chapterMatch ? chapterMatch[1] : (i + 1);
                    shortChapters.push("Chương " + chapterNum + " chỉ có " + charCount + " ký tự");
                }
            }
            if (shortChapters.length > 0) {
                detailedSummary += shortChapters.join("\n");
            }
            if (chapters.length > titles.length) {
                var remainingContent = chapters.slice(titles.length).join("\n\n");
                me.copyToClipboard(remainingContent);
            }
            jQuery("#qpContent").val(mainSummary);
            jQuery("#qpn").html(detailedSummary.replace(/\n/g, '<br>'));
            jQuery("#qpButtonSubmit").removeClass("btn-disable").addClass("btn-success");
        } catch (e) {
            console.log("Lỗi khi tách chương: " + e);
            jQuery("#qpn").html("Có lỗi xảy ra khi tách chương: " + e).addClass("text-danger");
        }
    }
};
if (window.location.href.includes('tangthuvien.net/message/successchapter')) {
    setTimeout(function () {
        var previousUrl = document.referrer;
        var storyId = '';
        if (previousUrl.includes('/dang-chuong/story/')) {
            var matches = previousUrl.match(/\/dang-chuong\/story\/(\d+)/);
            if (matches && matches[1]) {
                storyId = matches[1];
                window.location.href = 'https://tangthuvien.net/dang-chuong/story/' + storyId;
            }
        }
    }, 3000);
}
else if (window.location.href.includes('/story/') && window.location.href.includes('/danh-sach-chuong')) {
    setTimeout(function () {
        var matches = window.location.href.match(/\/story\/(\d+)/);
        if (matches && matches[1]) {
            var storyId = matches[1];
            window.location.href = 'https://tangthuvien.net/dang-chuong/story/' + storyId;
        }
    }, 3000);
} else {
    dăngnhanhTTV.init();
}