Đăng Nhanh TTV v2

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

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

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

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Đăng Nhanh TTV v2
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  Đăng truyện nhanh TTV với nhiều tính năng mới và tự động tách chương - phiên bản tối ưu
// @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==

(function() {
    'use strict';
    const HEADER_SIGN = "";
    const FOOTER_SIGN = "";
    const dăngnhanhTTV = {
        CONFIG: {
            YEAR_ALIVE: 2021,
            MAX_CHAPTER_POST: 10,
            MIN_CHARACTERS: 3000,
            MAX_CHARACTERS: 20000,
            SAFE_CHARACTERS: 15000
        },
        STATE: {
            CHAP_NUMBER: 1,
            CHAP_STT: 1,
            CHAP_SERIAL: 1,
            CHAP_NUMBER_ORIGINAL: 1,
            CHAP_STT_ORIGINAL: 1,
            CHAP_SERIAL_ORIGINAL: 1
        },
        ELEMENTS: {
            qpContent: null,
            qpButtonSubmit: null,
            qpButtonRemoveEmpty: null,
            qpn: null,
            characterCount: null
        },
        init: function() {
            try {
                const me = this;
                if (this.handleRedirects()) {
                    return;
                }
                this.initializeChapterValues();
                this.createInterface();
                this.addStyles();
                this.cacheElements();
                this.registerEvents();
                this.createListAddChapter(true);
                jQuery('#qpNumberOfChapter').attr('max', me.CONFIG.MAX_CHAPTER_POST);
                this.ELEMENTS.qpContent.focus();
            } catch (e) {
                console.error("Lỗi khởi tạo:", e);
            }
        },
        handleRedirects: function() {
            if (window.location.href.includes('tangthuvien.net/message/successchapter')) {
                setTimeout(function() {
                    const previousUrl = document.referrer;
                    if (previousUrl.includes('/dang-chuong/story/')) {
                        const matches = previousUrl.match(/\/dang-chuong\/story\/(\d+)/);
                        if (matches && matches[1]) {
                            window.location.href = 'https://tangthuvien.net/dang-chuong/story/' + matches[1];
                        }
                    }
                }, 3000);
                return true;
            } else if (window.location.href.includes('/story/') && window.location.href.includes('/danh-sach-chuong')) {
                setTimeout(function() {
                    const matches = window.location.href.match(/\/story\/(\d+)/);
                    if (matches && matches[1]) {
                        window.location.href = 'https://tangthuvien.net/dang-chuong/story/' + matches[1];
                    }
                }, 3000);
                return true;
            }
            return false;
        },
        cacheElements: function() {
            this.ELEMENTS.qpContent = jQuery("#qpContent");
            this.ELEMENTS.qpButtonSubmit = jQuery("#qpButtonSubmit");
            this.ELEMENTS.qpButtonRemoveEmpty = jQuery("#qpButtonRemoveEmpty");
            this.ELEMENTS.qpn = jQuery("#qpn");
            this.ELEMENTS.characterCount = jQuery(".character-count");
        },
        initializeChapterValues: function() {
            const chap_number = parseInt(jQuery('#chap_number').val());
            let chap_stt = parseInt(jQuery('.chap_stt1').val());
            let 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());
            }
            this.STATE.CHAP_NUMBER = this.STATE.CHAP_NUMBER_ORIGINAL = chap_number;
            this.STATE.CHAP_STT = this.STATE.CHAP_STT_ORIGINAL = chap_stt;
            this.STATE.CHAP_SERIAL = this.STATE.CHAP_SERIAL_ORIGINAL = chap_serial;
        },
        addNewChapter: function() {
            const me = this;
            if ((me.STATE.CHAP_NUMBER + 1) <= me.CONFIG.MAX_CHAPTER_POST) {
                me.updateChapNumber(true);
                const chap_vol = parseInt(jQuery('.chap_vol').val());
                const chap_vol_name = jQuery('.chap_vol_name').val();
                const html = `
                <div data-gen="MK_GEN" id="COUNT_CHAP_${me.STATE.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.STATE.CHAP_NUMBER}]" value="${me.STATE.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.STATE.CHAP_SERIAL}" required class="form-control" name="chap_number[${me.STATE.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.STATE.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.STATE.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.STATE.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.STATE.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.STATE.CHAP_NUMBER}]" placeholder="Quảng cáo" type="text"></textarea>
                        </div>
                    </div>
                </div>`;
                jQuery('#add-chap').before(html);
            } else {
                const chapterLeft = Math.max(0, me.CONFIG.MAX_CHAPTER_POST - me.STATE.CHAP_NUMBER);
                alert(`Bạn nên đăng tối đa ${me.CONFIG.MAX_CHAPTER_POST} chương một lần, số chương đã tạo ${me.STATE.CHAP_NUMBER} chương, bạn có thể đăng thêm ${chapterLeft} chương nữa.`);
            }
        },
        createListAddChapter: function(isSilent) {
            const me = this;
            const chapterAdd = parseInt(jQuery("#qpNumberOfChapter").val());

            if ((me.STATE.CHAP_NUMBER + chapterAdd) <= me.CONFIG.MAX_CHAPTER_POST) {
                for (let 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.CONFIG.MAX_CHAPTER_POST} chương một lần, số chương đã tạo ${me.STATE.CHAP_NUMBER} chương, bạn có thể đăng thêm ${me.CONFIG.MAX_CHAPTER_POST - me.STATE.CHAP_NUMBER} chương nữa.`);
            }
        },
        removeLastedPost: function() {
            const me = this;
            jQuery(`#COUNT_CHAP_${me.STATE.CHAP_NUMBER}_MK`).remove();
            me.updateChapNumber();
        },
        updateChapNumber: function(isAdd) {
            const me = this;
            try {
                if (isAdd) {
                    let chap_stt = parseInt(jQuery('.chap_stt1').val());
                    let 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.STATE.CHAP_STT = chap_stt;
                    me.STATE.CHAP_SERIAL = chap_serial;
                    me.STATE.CHAP_NUMBER++;
                    me.STATE.CHAP_STT++;
                    me.STATE.CHAP_SERIAL++;
                } else {
                    if (me.STATE.CHAP_NUMBER > me.STATE.CHAP_NUMBER_ORIGINAL) {
                        me.STATE.CHAP_NUMBER--;
                    }
                    if (me.STATE.CHAP_STT > me.STATE.CHAP_STT_ORIGINAL) {
                        me.STATE.CHAP_STT--;
                    }
                    if (me.STATE.CHAP_SERIAL > me.STATE.CHAP_SERIAL_ORIGINAL) {
                        me.STATE.CHAP_SERIAL--;
                    }
                }
                jQuery('#chap_number').val(me.STATE.CHAP_NUMBER);
                jQuery('#chap_stt').val(me.STATE.CHAP_STT);
                jQuery('#chap_serial').val(me.STATE.CHAP_SERIAL);
                jQuery('#countNumberPost').text(me.STATE.CHAP_NUMBER);
            } catch (e) {
                console.error("Lỗi cập nhật số chương:", e);
            }
        },
        createInterface: function() {
            const html = `
            <div id="HA">
                <div class="form-group"></div>
                <center>
                    <h3 style="color: #4285f4; margin-bottom: 15px; font-weight: 600;">📝 CÔNG CỤ ĐĂNG NHANH</h3>
                </center>
                <center>
                    <h4><span id="short-chapter-warning" style="display:none; color:#ea4335; padding: 8px; background-color: #ffebee; border-radius: 6px;"></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="character-count" style="text-align: right; font-size: 11px; color: #666; margin-top: 3px;">Số ký tự: 0</div>
                    <div class="form-group" id="qpAdv" class="form-control" rows="2"></div>
                    <div class="form-group" style="display: flex; justify-content: space-between; margin-top: 15px;">
                        <div>
                            <button type="button" id="qpButtonSubmit" class="btn btn-success">📤 Đăng chương</button>
                        </div>
                        <div>
                            <button type="button" id="qpButtonRemoveEmpty" class="btn btn-danger" style="display: none;">Xóa chương trống</button>
                            <button type="button" id="qpButtonAddEmpty" class="btn btn-outline">Xóa chương trống</button>
                        </div>
                    </div>
                    <div class="form-group">
                        <span id="qpn" style="margin:0px 15px;font-weight:500"></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>`;
            jQuery(".list-in-user").before(html);
        },
        addStyles: function() {
            const style = document.createElement('style');
            style.textContent = `
                #HA { 
                    background-color: #ffffff !important;
                    padding: 20px;
                    color: #333333 !important;
                    border-radius: 12px;
                    margin-bottom: 15px;
                    position: fixed;
                    right: 20px;
                    top: 50%;
                    transform: translateY(-50%);
                    max-width: 400px;
                    z-index: 9999;
                    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
                    font-family: "Segoe UI", Roboto, Arial, sans-serif;
                    transition: all 0.3s ease;
                }
                #HA > .form-group > div {
                    font-size: 14px;
                    color: #333333 !important;
                }
                #HA > p {
                    font-size: 14px;
                    color: #333333 !important;
                    text-align: right;
                }
                #HA .HA-option {
                    padding: 10px;
                    border: 1px solid #e0e0e0;
                    border-radius: 8px;
                    margin-bottom: 15px;
                    background-color: #f8f9fa;
                }
                #HA .HA-option-label {
                    width: 100%;
                    background-color: #4285f4;
                    color: white;
                    padding: 10px;
                    border-radius: 6px;
                    margin: 0 0 10px 0;
                    font-weight: 500;
                }
                #qpn {
                    max-height: 300px;
                    overflow-y: auto;
                    margin-top: 15px;
                    font-size: 13px;
                    padding: 10px;
                    background-color: #f5f8ff;
                    border-radius: 8px;
                }
                .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;
                }
                @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;
                    border: 2px solid #ea4335 !important;
                    border-radius: 8px !important;
                    background-color: rgba(255, 235, 238, 0.2) !important;
                }
                #short-chapter-warning {
                    animation: blink-red 2s infinite;
                    display: inline-block;
                    padding: 6px 10px;
                    border-radius: 4px;
                    font-size: 12px;
                }
                .form-control {
                    border: 1px solid #e0e0e0;
                    border-radius: 6px;
                    padding: 10px;
                    font-size: 14px;
                    transition: all 0.3s ease;
                }
                .form-control:focus {
                    border-color: #4285f4;
                    box-shadow: 0 0 5px rgba(66, 133, 244, 0.3);
                    outline: none;
                }
                .character-count, .chapter-character-count {
                    text-align: right;
                    font-size: 14px;
                    color: #666;
                    margin-top: 5px;
                    padding-right: 8px;
                    font-family: "Segoe UI", Roboto, Arial, sans-serif;
                    font-weight: 600;
                }
                .btn {
                    padding: 8px 16px;
                    border-radius: 6px;
                    font-weight: 500;
                    cursor: pointer;
                    transition: all 0.2s ease;
                    border: none;
                    font-size: 14px;
                    margin: 5px;
                }
                .btn-success {
                    background-color: #4285f4;
                    color: white;
                }
                .btn-success:hover {
                    background-color: #3367d6;
                }
                .btn-danger {
                    background-color: #f5f5f5;
                    color: #333333;
                    border: 1px solid #ccc;
                    font-weight: normal;
                }
                .btn-danger:hover {
                    background-color: #e9e9e9;
                    color: #333333;
                    border: 1px solid #bbb;
                }
                .btn-default {
                    background-color: #f1f3f4;
                    color: #333333;
                }
                .btn-default:hover {
                    background-color: #e8eaed;
                }
                /* Styles for summary sections */
                .summary-section {
                    padding: 6px 8px;
                    margin-bottom: 5px;
                    border-radius: 4px;
                    background-color: #ffffff;
                    border-left: 3px solid #4285f4;
                    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
                    font-size: 12px;
                }
                .summary-section.warning {
                    border-left-color: #fbbc05;
                    background-color: #fffde7;
                }
                .summary-section.error {
                    border-left-color: #ea4335;
                    background-color: #fef2f2;
                }
                .summary-label {
                    font-weight: 600;
                    color: #202124;
                    display: inline-block;
                    min-width: 110px;
                    font-size: 12px;
                }
                .summary-value {
                    color: #3c4043;
                    font-weight: 500;
                    font-size: 12px;
                }
                .summary-details {
                    margin: 2px 0 2px 8px;
                    padding: 2px 0 2px 6px;
                    border-left: 2px solid #e0e0e0;
                    font-size: 11px;
                }
                .detail-item {
                    padding: 1px 0;
                    color: #5f6368;
                    font-size: 11px;
                }
                #qpn {
                    max-height: 250px;
                    overflow-y: auto;
                    margin-top: 10px;
                    font-size: 12px;
                    padding: 8px;
                    background-color: #f5f8ff;
                    border-radius: 6px;
                }
            `;
            document.head.appendChild(style);
            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);
        },
        registerEvents: function() {
            const me = this;
            this.ELEMENTS.qpContent.on("input", function() {
                me.updateCharacterCount(jQuery(this).val().length, me.ELEMENTS.characterCount);
            });
            jQuery(document).on("input", "[name^=introduce]", function() {
                const text = jQuery(this).val().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim();
                const charCount = text.length;
                let charCountElement = jQuery(this).next('.chapter-character-count');
                if (charCountElement.length === 0) {
                    charCountElement = jQuery('<div class="chapter-character-count" style="text-align: right; font-size: 11px; margin-top: 3px; padding-right: 5px;"></div>');
                    jQuery(this).after(charCountElement);
                }
                me.updateCharacterCount(charCount, charCountElement);
            });
            this.ELEMENTS.qpContent.on("paste", function(e) {
                jQuery(this).val("");
                me.showProcessingNotification();
                setTimeout(function() {
                    const text = me.ELEMENTS.qpContent.val();
                    me.updateCharacterCount(text.length, me.ELEMENTS.characterCount);
                }, 100);
                setTimeout(function() {
                    me.splitChapters();
                    jQuery("#processing-notification").fadeOut(300, function() {
                        jQuery(this).remove();
                    });
                    me.showCompletionNotification();
                }, 500);
            });
            jQuery('#qpButtonRemoveEmpty').on('click', function(e) {
                e.preventDefault();
                me.removeEmptyList();
            });
            jQuery('#qpButtonAddEmpty').on('click', function(e) {
                e.preventDefault();
                me.addNewChapter();
            });
            this.ELEMENTS.qpButtonSubmit.on('click', function(e) {
                e.preventDefault();
                const titles = jQuery("[name^=chap_name]");
                const contents = jQuery("[name^=introduce]");
                const advs = jQuery("[name^=adv]");
                const advContent = jQuery("#qpAdv").val();
                const st = jQuery('#qpSplitValueReplace').val().trim();
                me.fillEmptyForms(titles, contents, advs, advContent, st);
                jQuery('form button[type=submit]')[0].click();
            });
        },
        showProcessingNotification: function() {
            const 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.8)",
                    color: "white",
                    padding: "15px 25px",
                    borderRadius: "8px",
                    zIndex: "10000",
                    fontSize: "16px",
                    fontWeight: "500",
                    boxShadow: "0 4px 15px rgba(0,0,0,0.2)"
                }
            });
            jQuery("body").append(processingMsg);
        },
        showCompletionNotification: function() {
            const completeMsg = jQuery("<div>", {
                id: "complete-notification",
                html: "<span style='font-size:18px;margin-right:8px;'>✅</span> Đã tách chương tự động!",
                css: {
                    position: "fixed",
                    top: "20px",
                    right: "20px",
                    backgroundColor: "#4CAF50",
                    color: "white",
                    padding: "12px 20px",
                    borderRadius: "8px",
                    zIndex: "10000",
                    fontSize: "14px",
                    fontWeight: "500",
                    boxShadow: "0 4px 10px rgba(0,0,0,0.15)",
                    display: "flex",
                    alignItems: "center"
                }
            });
            jQuery("body").append(completeMsg);
            completeMsg.fadeIn(300).delay(2000).fadeOut(500, function() {
                jQuery(this).remove();
            });
        },
        updateCharacterCount: function(charCount, element) {
            if (element === this.ELEMENTS.characterCount) {
                element.html("<strong style='font-size: 14px;'>Số ký tự: " + charCount.toLocaleString('vi-VN') + "</strong>");
            } else {
                element.html("<strong style='font-size: 14px;'>Số ký tự: " + charCount.toLocaleString('vi-VN') + "/20.000</strong>");
            }
            if (charCount < this.CONFIG.MIN_CHARACTERS) {
                element.css("color", "#ea4335");
            } else if (charCount > this.CONFIG.MAX_CHARACTERS) {
                element.css("color", "#fbbc05");
            } else {
                element.css("color", "#34a853");
            }
        },
        ucFirst: function(str) {
            if (str && typeof str === 'string' && str.length > 0) {
                return str.charAt(0).toUpperCase() + str.slice(1);
            }
            return str;
        },
        copyToClipboard: function(text) {
            navigator.clipboard.writeText(text).catch(err => {
                const 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);
            });
        },
        removeEmptyList: function() {
            try {
                const me = this;
                const titles = jQuery("[name^=chap_name]");
                const contents = jQuery("[name^=introduce]");
                let count = 0;
                this.ELEMENTS.qpn.html('');
                if (titles && titles.length) {
                    for (let i = 0; i < titles.length; i++) {
                        const t = titles[i];
                        const c = contents[i];
                        if (t && (!t.value || (c && !c.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').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');
                const updatedTitles = jQuery("[name^=chap_name]");
                const updatedContents = jQuery("[name^=introduce]");
                const updatedAdvs = jQuery("[name^=adv]");
                const advContent = jQuery("#qpAdv").val();
                const st = jQuery('#qpSplitValueReplace').val().trim();
                let stillHasEmptyChapters = false;
                for (let i = 0; i < updatedTitles.length; i++) {
                    const t = updatedTitles[i];
                    const c = updatedContents[i];
                    if (t && (!t.value || (c && !c.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim()))) {
                        stillHasEmptyChapters = true;
                        break;
                    }
                }
                if (stillHasEmptyChapters) {
                    this.ELEMENTS.qpButtonRemoveEmpty.show();
                    jQuery('#qpButtonAddEmpty').hide();
                } else {
                    this.ELEMENTS.qpButtonRemoveEmpty.hide();
                    jQuery('#qpButtonAddEmpty').show();
                }
                me.fillEmptyForms(updatedTitles, updatedContents, updatedAdvs, advContent, st);
            } catch (e) {
                console.error("Lỗi khi xóa chương trống:", e);
            }
        },
        fillEmptyForms: function(titles, contents, advs, advContent, st) {
            try {
                const maxIterations = 3;
                let iteration = 0;
                let hasEmptyForms = true;
                while (hasEmptyForms && iteration < maxIterations) {
                    hasEmptyForms = false;
                    for (let i = 0; i < titles.length; i++) {
                        const currentTitle = titles[i];
                        const currentContent = contents[i];

                        if (currentTitle && (!currentTitle.value || (currentContent && !currentContent.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim()))) {
                            hasEmptyForms = true;

                            let foundNextValid = false;
                            for (let j = i + 1; j < titles.length; j++) {
                                const nextTitle = titles[j];
                                const nextContent = contents[j];

                                if (nextTitle && nextTitle.value && nextContent && nextContent.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').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++;
                }
                let emptyFormCount = 0;
                for (let i = 0; i < titles.length; i++) {
                    const currentTitle = titles[i];
                    const currentContent = contents[i];
                    if (currentTitle && (!currentTitle.value || (currentContent && !currentContent.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim()))) {
                        emptyFormCount++;
                    }
                }
                if (emptyFormCount > 0) {
                    this.ELEMENTS.qpn.html(this.ELEMENTS.qpn.html() + `<br><b style='color:red'>Cảnh báo: Vẫn còn ${emptyFormCount} chương trống.</b>`);
                    this.ELEMENTS.qpButtonRemoveEmpty.show();
                    jQuery('#qpButtonAddEmpty').hide();
                } else {
                    this.ELEMENTS.qpButtonRemoveEmpty.hide();
                    jQuery('#qpButtonAddEmpty').show();
                }
            } catch (e) {
                console.error("Lỗi khi đẩy chương lên form trống:", e);
            }
        },
        splitChapters: function() {
            try {
                const me = this;
                window.shortChapterNotified = false;
                const warningEl = document.getElementById('short-chapter-warning');
                if (warningEl) {
                    warningEl.style.display = 'none';
                }
                const mainContentText = this.ELEMENTS.qpContent.val();
                const mainContentLength = mainContentText.length;
                this.updateCharacterCount(mainContentLength, this.ELEMENTS.characterCount);
                const content = this.ELEMENTS.qpContent.val();
                const st = jQuery('#qpSplitValueReplace').val().trim();
                const advContent = jQuery("#qpAdv").val();
                const lines = content.split('\n');
                const chapters = [];
                let currentChapter = [];
                const regex = /^\s*[Cc]hương\s*\d+\s*:/;
                for (let i = 0; i < lines.length; i++) {
                    const 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'));
                }
                const filteredChapters = chapters.filter(function(chapter) {
                    const lines = chapter.split('\n');
                    return lines.some(function(line, index) {
                        return index > 0 && line.trim().length > 0;
                    });
                });
                let i = 0;
                const processedChapters = [];

                while (i < filteredChapters.length) {
                    if (filteredChapters[i].length > this.CONFIG.MAX_CHARACTERS) {
                        const largeChapter = filteredChapters[i];
                        const lines = largeChapter.split('\n');
                        const chapterTitle = lines.shift();
                        const contentToSplit = lines.join('\n');
                        const contentLength = contentToSplit.length;
                        const numSubChapters = Math.ceil(contentLength / this.CONFIG.SAFE_CHARACTERS);
                        const chunkSize = Math.floor(contentLength / numSubChapters);
                        let startPos = 0;
                        for (let j = 0; j < numSubChapters; j++) {
                            let endPos = (j === numSubChapters - 1) ? contentLength : startPos + chunkSize;
                            if (j < numSubChapters - 1) {
                                const lookAhead = Math.min(200, contentLength - endPos);
                                const segment = contentToSplit.substring(endPos, endPos + lookAhead);
                                const sentenceEnd = segment.search(/[.!?][^.!?]*$/);
                                if (sentenceEnd !== -1) {
                                    endPos += sentenceEnd + 1;
                                }
                            }
                            const subContent = contentToSplit.substring(startPos, endPos);
                            const subTitle = `${chapterTitle.trim()} (Phần ${j + 1}/${numSubChapters})`;
                            processedChapters.push(subTitle + "\n" + subContent);
                            startPos = endPos;
                        }
                    } else {
                        processedChapters.push(filteredChapters[i]);
                    }
                    i++;
                }
                const titles = jQuery("[name^=chap_name]");
                const contents = jQuery("[name^=introduce]");
                const advs = jQuery("[name^=adv]");
                let validChapters = 0;
                const shortChapters = [];
                const splitChapterGroups = [];
                const duplicateTitles = [];
                const titleMap = {};
                for (let i = 0; i < Math.min(processedChapters.length, titles.length); i++) {
                    const chapterLines = processedChapters[i].split('\n');
                    const title = chapterLines.shift().trim();
                    const content = chapterLines.join('\n');
                    if (content) {
                        validChapters++;
                        let processedTitle = title;
                        if (title.includes(':')) {
                            processedTitle = title.split(':').slice(1).join(':').trim();
                        }
                        processedTitle = this.ucFirst(processedTitle);
                        if (processedTitle.toLowerCase().startsWith(st.toLowerCase())) {
                            titles[i].value = processedTitle;
                        } else {
                            titles[i].value = st + " " + processedTitle;
                        }
                        contents[i].value = HEADER_SIGN + "\r\n" + content + "\r\n" + FOOTER_SIGN;
                        advs[i].value = advContent;
                        const contentWithoutEmpty = content.split('\n')
                            .filter(line => line.trim().length > 0)
                            .join('\n');
                        const charCount = contentWithoutEmpty.length;
                        let charCountElement = jQuery(contents[i]).next('.chapter-character-count');
                        if (charCountElement.length === 0) {
                            charCountElement = jQuery('<div class="chapter-character-count" style="text-align: right; font-size: 11px; margin-top: 3px; padding-right: 5px;"></div>');
                            jQuery(contents[i]).after(charCountElement);
                        }
                        this.updateCharacterCount(charCount, charCountElement);
                        if (charCount < this.CONFIG.MIN_CHARACTERS) {
                            contents[i].style.border = '3px solid red';
                            shortChapters.push(title);
                        }
                        const titleText = titles[i].value.toLowerCase();
                        if (titleMap[titleText]) {
                            duplicateTitles.push(titles[i].value);
                        } else {
                            titleMap[titleText] = true;
                        }
                        if (title.includes(" (Phần ")) {
                            const parts = title.match(/\(Phần (\d+)\/(\d+)\)/);
                            if (parts && parts[2] && parts[1] === "1") {
                                const chapterName = title.replace(/\s*\(Phần \d+\/\d+\)/, "");
                                splitChapterGroups.push({
                                    name: chapterName,
                                    totalParts: parseInt(parts[2])
                                });
                            }
                        }
                    }
                }
                const totalProcessedChapters = processedChapters.length;
                let splitChaptersCount = 0;
                let largeChapterCount = 0;
                let totalParts = 0;
                for (let i = 0; i < processedChapters.length; i++) {
                    const firstLine = processedChapters[i].split('\n')[0];
                    if (firstLine && firstLine.includes(" (Phần ")) {
                        splitChaptersCount++;
                        const parts = firstLine.match(/\(Phần (\d+)\/(\d+)\)/);
                        if (parts && parts[2]) {
                            const totalPartsInChapter = parseInt(parts[2]);
                            if (parts[1] === "1") {
                                largeChapterCount++;
                                totalParts += totalPartsInChapter;
                            }
                        }
                    }
                }
                if (processedChapters.length > titles.length) {
                    const remainingContent = processedChapters.slice(titles.length).join("\n\n");
                    this.copyToClipboard(remainingContent);
                }
                let detailedSummary = "";
                detailedSummary += `<div class='summary-section' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Tổng số chương:</span> <span class='summary-value'>${totalProcessedChapters}</span></div>`;
                detailedSummary += `<div class='summary-section' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Đã xử lý:</span> <span class='summary-value'>${Math.min(processedChapters.length, titles.length)} chương</span></div>`;

                if (processedChapters.length > titles.length) {
                    detailedSummary += `<div class='summary-section' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Đã lưu vào Clipboard:</span> <span class='summary-value'>${processedChapters.length - titles.length} chương</span></div>`;
                }
                if (largeChapterCount > 0) {
                    detailedSummary += `<div class='summary-section warning' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Chương dài:</span> <span class='summary-value'>${largeChapterCount} chia thành ${totalParts} phần</span></div>`;

                    if (splitChapterGroups.length > 0 && splitChapterGroups.length <= 3) {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < splitChapterGroups.length; i++) {
                            const chapterMatch = splitChapterGroups[i].name.match(/[Cc]hương\s*(\d+):/);
                            const chapterNum = chapterMatch ? chapterMatch[0] : "Chương";
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${chapterNum} chia thành ${splitChapterGroups[i].totalParts} phần</div>`;
                        }
                        detailedSummary += `</div>`;
                    } else if (splitChapterGroups.length > 3) {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < 3; i++) {
                            const chapterMatch = splitChapterGroups[i].name.match(/[Cc]hương\s*(\d+):/);
                            const chapterNum = chapterMatch ? chapterMatch[0] : "Chương";
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${chapterNum} chia thành ${splitChapterGroups[i].totalParts} phần</div>`;
                        }
                        detailedSummary += `<div class='detail-item' style='padding:1px 0'>... và ${splitChapterGroups.length - 3} chương khác</div>`;
                        detailedSummary += `</div>`;
                    }
                }
                if (duplicateTitles.length > 0) {
                    detailedSummary += `<div class='summary-section error' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Chương trùng lặp:</span> <span class='summary-value'>${duplicateTitles.length} chương</span></div>`;
                    if (duplicateTitles.length <= 3) {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < duplicateTitles.length; i++) {
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${duplicateTitles[i]}</div>`;
                        }
                        detailedSummary += `</div>`;
                    } else {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < 3; i++) {
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${duplicateTitles[i]}</div>`;
                        }
                        detailedSummary += `<div class='detail-item' style='padding:1px 0'>... và ${duplicateTitles.length - 3} chương khác</div>`;
                        detailedSummary += `</div>`;
                    }
                }
                if (shortChapters.length > 0) {
                    detailedSummary += `<div class='summary-section error' style='font-size:12px;padding:6px 8px;margin-bottom:5px'><span class='summary-label'>Chương ngắn:</span> <span class='summary-value'>${shortChapters.length} chương</span></div>`;
                    if (shortChapters.length <= 3) {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < shortChapters.length; i++) {
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${shortChapters[i]}</div>`;
                        }
                        detailedSummary += `</div>`;
                    } else {
                        detailedSummary += `<div class='summary-details' style='font-size:11px;margin:2px 0 2px 8px;padding:2px 0 2px 6px'>`;
                        for (let i = 0; i < 3; i++) {
                            detailedSummary += `<div class='detail-item' style='padding:1px 0'>${shortChapters[i]}</div>`;
                        }
                        detailedSummary += `<div class='detail-item' style='padding:1px 0'>... và ${shortChapters.length - 3} chương khác</div>`;
                        detailedSummary += `</div>`;
                    }
                }
                const mainSummary = `Đã xử lý ${totalProcessedChapters} chương\nĐã lấy ${Math.min(processedChapters.length, titles.length)} chương` 
                    + (processedChapters.length > titles.length ? `\nĐã lưu ${processedChapters.length - titles.length} chương vào Clipboard` : '');
                this.ELEMENTS.qpContent.val(mainSummary);
                this.ELEMENTS.qpn.html(detailedSummary);
                this.ELEMENTS.qpButtonSubmit.removeClass("btn-disable").addClass("btn-success");
                let emptyChaptersExist = false;
                for (let i = 0; i < titles.length; i++) {
                    const currentTitle = titles[i];
                    const currentContent = contents[i];
                    if (currentTitle && (!currentTitle.value || (currentContent && !currentContent.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim()))) {
                        emptyChaptersExist = true;
                        break;
                    }
                }
                let hasEmptyChapters = false;
                for (let i = 0; i < titles.length; i++) {
                    const t = titles[i];
                    const c = contents[i];
                    if (t && (!t.value || (c && !c.value.trim().replace(HEADER_SIGN, '').replace(FOOTER_SIGN, '').trim()))) {
                        hasEmptyChapters = true;
                        break;
                    }
                }
                if (hasEmptyChapters) {
                    me.ELEMENTS.qpButtonRemoveEmpty.show();
                    jQuery('#qpButtonAddEmpty').hide();
                } else {
                    me.ELEMENTS.qpButtonRemoveEmpty.hide();
                    jQuery('#qpButtonAddEmpty').show();
                }
            } catch (e) {
                console.error("Lỗi khi tách chương:", e);
                this.ELEMENTS.qpn.html(`<div class='summary-section error'><span class='summary-label'>Lỗi:</span> <span class='summary-value'>${e}</span></div>`).addClass("text-danger");
            }
        }
    };
    dăngnhanhTTV.init();
})();