TTV

Công cụ đăng chương hiện đại cho Tàng Thư Viện với UI/UX được tối ưu

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         TTV
// @namespace    http://tampermonkey.net/
// @version      3.5
// @description  Công cụ đăng chương hiện đại cho Tàng Thư Viện với UI/UX được tối ưu
// @author       HA
// @match        https://tangthuvien.net/dang-chuong/story/*
// @match        https://tangthuvien.net/danh-sach-chuong/story/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @required     https://code.jquery.com/jquery-3.2.1.min.js
// ==/UserScript==

(function() {
    'use strict';
    if (window.location.href.includes('/danh-sach-chuong/story/')) {
        const storyId = window.location.pathname.split('/').pop();
        setTimeout(() => {
            window.location.href = `https://tangthuvien.net/dang-chuong/story/${storyId}`;
        }, 3000);
        return;
    }

    const HEADER_SIGN = "";
    const FOOTER_SIGN = "";
    const MAX_CHAPTER_POST = 10;
    GM_addStyle(`
        /* Vị trí và giao diện của công cụ đăng nhanh */
        #modern-uploader {
            background: linear-gradient(145deg, #ffffff, #f5f8ff);
            padding: 28px;
            border-radius: 16px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
            position: fixed;
            right: 25px;
            top: 50%;
            transform: translateY(-50%);
            width: 450px;
            max-height: 92vh;
            overflow-y: auto;
            z-index: 1000;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            border: 1px solid #e0e0e0;
            transition: all 0.3s ease;
        }
        #modern-uploader:hover {
            box-shadow: 0 12px 28px rgba(0, 0, 0, 0.15);
        }
        #modern-uploader::-webkit-scrollbar {
            width: 8px;
        }
        #modern-uploader::-webkit-scrollbar-track {
            background: #f5f5f5;
            border-radius: 8px;
        }
        #modern-uploader::-webkit-scrollbar-thumb {
            background: linear-gradient(180deg, #4285f4, #34a853);
            border-radius: 8px;
        }
        #modern-uploader::-webkit-scrollbar-thumb:hover {
            background: linear-gradient(180deg, #1a73e8, #27833c);
        }
        @keyframes shortChapterBlink {
            0% { background-color: rgba(255, 0, 0, 0.1); }
            50% { background-color: rgba(255, 0, 0, 0.2); }
            100% { background-color: rgba(255, 0, 0, 0.1); }
        }
        textarea[name^="introduce"] {
            transition: all 0.3s ease;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
        }
        textarea[name^="introduce"].short-chapter {
            animation: shortChapterBlink 1s infinite;
            border: 2px solid #ff0000 !important;
            background-color: rgba(255, 0, 0, 0.1) !important;
        }
        .chapter-character-count {
            text-align: right;
            font-size: 12px;
            margin-top: 10px;
            color: #666;
            font-weight: 500;
        }
        .short-chapters-warning {
            color: #ff0000;
            font-weight: bold;
            animation: shortChapterBlink 1s infinite;
        }

        .button-container {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 14px;
            margin-top: 24px;
            flex-wrap: wrap;
        }
        #modern-uploader .btn {
            padding: 12px 20px;
            border-radius: 10px;
            cursor: pointer;
            font-weight: 600;
            font-size: 14px;
            transition: all 0.3s ease;
            border: none;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            display: flex;
            align-items: center;
            gap: 6px;
        }
        #modern-uploader .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 10px rgba(0,0,0,0.15);
        }
        #modern-uploader .btn:active {
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        #modern-uploader .btn-primary {
            background: linear-gradient(140deg, #4285f4, #1a73e8);
            color: white;
        }
        #modern-uploader .btn-success {
            background: linear-gradient(140deg, #34a853, #27833c);
            color: white;
        }
        #modern-uploader .btn-danger {
            background: linear-gradient(140deg, #ea4335, #d32f2f);
            color: white;
        }
        #modern-uploader .btn-secondary {
            background: linear-gradient(140deg, #9e9e9e, #757575);
            color: white;
        }
        #modern-uploader .btn-warning {
            background: linear-gradient(140deg, #fbbc05, #f5a623);
            color: #212529;
        }
        #modern-uploader .btn-info {
            background: linear-gradient(140deg, #17a2b8, #0097a7);
            color: white;
        }
        #modern-uploader .form-control {
            width: 100%;
            padding: 16px;
            border: 1px solid #ddd;
            border-radius: 10px;
            margin-bottom: 18px;
            font-size: 15px;
            transition: all 0.3s ease;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        #modern-uploader .form-control:focus {
            border-color: #4285f4;
            outline: none;
            box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.2);
        }
        #modern-uploader .loading-overlay {
            position: fixed;
            inset: 0;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 9999;
            backdrop-filter: blur(5px);
        }
        #modern-uploader .loading-spinner {
            width: 60px;
            height: 60px;
            border: 5px solid rgba(255, 255, 255, 0.3);
            border-radius: 50%;
            border-top-color: #ffffff;
            animation: spin 1s linear infinite;
            box-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
        }
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
        /* Checkbox tự động */
        #modern-uploader .checkbox-container {
            display: flex;
            justify-content: center;
            align-items: center;
            margin-bottom: 20px;
            background: linear-gradient(145deg, #f8f9fa, #f1f3f5);
            border-radius: 12px;
            padding: 14px;
            border: 1px solid #e9ecef;
            position: relative;
            overflow: hidden;
        }
        #modern-uploader .checkbox-container::before {
            content: '';
            position: absolute;
            width: 100%;
            height: 3px;
            bottom: 0;
            left: 0;
            background: linear-gradient(90deg, #4285f4, #34a853, #fbbc05, #ea4335);
            opacity: 0.7;
        }
        #qpOptionLoop {
            margin-right: 10px;
            width: 18px;
            height: 18px;
            cursor: pointer;
            accent-color: #4285f4;
        }
        /* Header styling */
        #modern-uploader .text-center {
            text-align: center;
        }
        #modern-uploader .uploader-header {
            margin-bottom: 25px;
            position: relative;
        }
        #modern-uploader .uploader-header::after {
            content: '';
            position: absolute;
            bottom: -10px;
            left: 50%;
            transform: translateX(-50%);
            width: 80%;
            height: 3px;
            background: linear-gradient(90deg, transparent, #4285f4, transparent);
            border-radius: 3px;
        }
        #modern-uploader h3 {
            color: #4285f4;
            font-weight: 700;
            font-size: 22px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            margin: 0;
            padding: 0;
            letter-spacing: 0.5px;
        }
        /* Notification styling */
        #modern-uploader .notification-container {
            width: 100%;
            padding: 14px 0;
            margin-top: 18px;
            text-align: left;
            border-top: 1px solid rgba(0,0,0,0.06);
        }
        #modern-uploader .notification-success,
        #modern-uploader .notification-error,
        #modern-uploader .notification-warning,
        #modern-uploader .notification-info {
            padding: 14px 18px;
            border-radius: 12px;
            font-size: 14px;
            font-weight: 500;
            box-shadow: 0 4px 12px rgba(0,0,0,0.08);
            display: inline-block;
            max-width: 100%;
            margin: 0;
            word-break: break-word;
            animation: fadeInUp 0.4s ease;
            line-height: 1.5;
        }
        @keyframes fadeInUp {
            from { opacity: 0; transform: translateY(15px); }
            to { opacity: 1; transform: translateY(0); }
        }
        #modern-uploader .notification-success {
            background: linear-gradient(145deg, #e8f5e9, #c8e6c9);
            color: #2e7d32;
            border-left: 4px solid #4caf50;
        }
        #modern-uploader .notification-error {
            background: linear-gradient(145deg, #ffebee, #ffcdd2);
            color: #c62828;
            border-left: 4px solid #f44336;
        }
        #modern-uploader .notification-warning {
            background: linear-gradient(145deg, #fff8e1, #ffecb3);
            color: #f57f17;
            border-left: 4px solid #ffb300;
        }
        #modern-uploader .notification-info {
            background: linear-gradient(145deg, #e3f2fd, #bbdefb);
            color: #1565c0;
            border-left: 4px solid #2196f3;
        }
        /* Google-style waves */
        @keyframes wave-animation {
            0% {transform: translateX(-100%);}
            100% {transform: translateX(100%);}
        }
        #modern-uploader .wave-bottom {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 5px;
            overflow: hidden;
            z-index: 1;
        }
        #modern-uploader .wave-bottom::after {
            content: '';
            position: absolute;
            width: 200%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(66, 133, 244, 0.3), transparent);
            animation: wave-animation 2s infinite linear;
        }
    `);

    function showNotification(message, type) {
        jQuery('#modern-uploader .notification-container').remove();
        const container = jQuery("<div>", {
            class: "notification-container"
        });
        const notification = jQuery("<div>", {
            class: `notification-${type}`
        });
        const lines = message.split('\n');
        lines.forEach((line, index) => {
            notification.append(jQuery("<div>").html(line));
        });
        container.append(notification);
        jQuery("#modern-uploader .button-container").after(container);
        notification.fadeIn(300);
    }

    function createChapterHTML(chapNum) {
        const chap_vol = parseInt(jQuery('.chap_vol').val()) || 1;
        const chap_vol_name = jQuery('.chap_vol_name').val() || '';
        return `
        <div data-gen="MK_GEN" id="COUNT_CHAP_${chapNum}_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[${chapNum}]" value="${dangNhanhTTV.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="${dangNhanhTTV.STATE.CHAP_SERIAL}" required class="form-control" name="chap_number[${chapNum}]" 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[${chapNum}]" 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[${chapNum}]" 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[${chapNum}]" 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[${chapNum}]" rows="20" placeholder="Nội dung" type="text"></textarea>
                    <div class="chapter-character-count"></div>
                </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[${chapNum}]" placeholder="Quảng cáo" type="text"></textarea>
                </div>
            </div>
        </div>`;
    }

    function setupCharacterCounter() {
        jQuery(document).on("input", "[name^=introduce]", function() {
            const text = jQuery(this).val();
            const charCount = text.length;
            let charCountElement = jQuery(this).next('.chapter-character-count');
            if (charCountElement.length === 0) {
                charCountElement = jQuery('<div class="chapter-character-count"></div>');
                jQuery(this).after(charCountElement);
            }
            if(charCount < 3000) {
                jQuery(this).addClass('short-chapter');
                charCountElement.html(`<span class="short-chapters-warning">${charCount.toLocaleString()}/40.000 ký tự</span>`);
            } else {
                jQuery(this).removeClass('short-chapter');
                if(charCount > 40000) {
                    charCountElement.html(`<span style="color: #fbbc05;">${charCount.toLocaleString()}/40.000 ký tự</span>`);
                } else {
                    charCountElement.html(`<span style="color: #34a853;">${charCount.toLocaleString()}/40.000 ký tự</span>`);
                }
            }
        });
    }

    function validateChapterLengths() {
        let hasError = false;
        jQuery('form[name="postChapForm"] .chapter-detail').each(function() {
            const form = this;
            const contentTextarea = form.querySelector('textarea[name^="introduce"]');
            const content = contentTextarea.value;
            if (content.length < 3000) {
                jQuery(contentTextarea).addClass('short-chapter');
                let warningIcon = form.querySelector('.warning-icon');
                if (!warningIcon) {
                    warningIcon = document.createElement('div');
                    warningIcon.className = 'warning-icon';
                    warningIcon.innerHTML = '⚠️';
                    contentTextarea.parentNode.appendChild(warningIcon);
                }
                hasError = true;
            } else {
                jQuery(contentTextarea).removeClass('short-chapter');
                const warningIcon = form.querySelector('.warning-icon');
                if (warningIcon) {
                    warningIcon.remove();
                }
            }
        });
        return !hasError;
    }

    const dangNhanhTTV = {
        STATE: {
            CHAP_NUMBER: 1,
            CHAP_STT: 1,
            CHAP_SERIAL: 1,
            CHAP_NUMBER_ORIGINAL: 1,
            CHAP_STT_ORIGINAL: 1,
            CHAP_SERIAL_ORIGINAL: 1,
            AUTO_POST: false,
            TOTAL_CHAPTERS: 0,
            POSTED_CHAPTERS: 0
        },
        ELEMENTS: {
            qpContent: null,
            qpButtonSubmit: null,
            qpButtonRemoveEmpty: null,
            qpButtonReset: null,
            qpButtonPaste: null,
            qpButtonAutoPost: null,
            qpOptionLoop: null
        },
        init: function() {
            try {
                console.log('[TTV-DEBUG] Script bắt đầu khởi tạo...');
                console.log('[TTV-DEBUG] Phiên bản script: 3.0');
                this.initializeChapterValues();
                console.log('[TTV-DEBUG] Đã khởi tạo giá trị chương');

                // Khôi phục trạng thái tự động đăng
                this.loadAutoPostState();
                console.log('[TTV-DEBUG] Đã khôi phục trạng thái tự động đăng');

                this.createInterface();
                console.log('[TTV-DEBUG] Đã tạo giao diện');
                this.cacheElements();
                console.log('[TTV-DEBUG] Đã cache các elements');
                this.registerEvents();
                console.log('[TTV-DEBUG] Đã đăng ký các events');
                console.log('[TTV-DEBUG] Script đã khởi động thành công');
                showNotification('Công cụ đã chạy thành công', 'success');

                // Cập nhật hiển thị nút tự động đăng
                if (this.STATE.AUTO_POST) {
                    this.ELEMENTS.qpButtonAutoPost.text(`🔄 TỰ ĐỘNG (${this.STATE.POSTED_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS})`);
                    this.ELEMENTS.qpButtonAutoPost.removeClass('btn-warning').addClass('btn-info');
                }

                // Khôi phục trạng thái chế độ tự động đăng
                const isAutoMode = localStorage.getItem('TTV_AUTO_MODE') === 'true';
                if (isAutoMode) {
                    this.ELEMENTS.qpOptionLoop.prop('checked', true);
                    this.toggleAutoMode(); // Áp dụng giao diện theo chế độ
                }
            } catch (e) {
                console.error('[TTV-ERROR] Lỗi khởi tạo:', e);
                showNotification('Có lỗi khi khởi tạo Script', 'error');
            }
        },

        loadAutoPostState: function() {
            // Khôi phục trạng thái tự động đăng từ localStorage
            const autoPost = localStorage.getItem('TTV_AUTO_POST') === 'true';
            this.STATE.AUTO_POST = autoPost;

            if (autoPost) {
                this.STATE.TOTAL_CHAPTERS = parseInt(localStorage.getItem('TTV_TOTAL_CHAPTERS') || '0');
                this.STATE.POSTED_CHAPTERS = parseInt(localStorage.getItem('TTV_POSTED_CHAPTERS') || '0');

                console.log(`[TTV-DEBUG] Khôi phục tự động đăng: ${this.STATE.POSTED_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS}`);
            }
        },

        createInterface: function() {
            const html = `
            <div id="modern-uploader">
                <div class="uploader-header">
                    <h3>📚 CÔNG CỤ ĐĂNG CHƯƠNG</h3>
                </div>
                <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>
                <div class="checkbox-container">
                    <input type="checkbox" id="qpOptionLoop">
                    <label for="qpOptionLoop" style="color: #1a73e8; font-weight: 600; margin-left: 8px;">Chế độ tự động đăng</label>
                </div>
                <div class="button-container">
                    <button class="btn btn-primary" id="qpButtonPaste">📋 Dán nội dung</button>
                    <button class="btn btn-success" id="qpButtonSubmit">📤 Đăng chương</button>
                    <button class="btn btn-danger" id="qpButtonRemoveEmpty" style="display: none;">🗑️ Ẩn chương trống</button>
                    <button class="btn btn-warning" id="qpButtonAutoPost" style="display: none;">🔄 TỰ ĐỘNG (TẮT)</button>
                    <button class="btn btn-secondary" id="qpButtonReset" style="display: none;">🔁 Reset đếm</button>
                </div>
                <div class="notification-container"></div>
                <div class="wave-bottom"></div>
            </div>`;

            jQuery(".list-in-user").before(html);
        },

        initializeChapterValues: function() {
            try {
                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 || 1;
                this.STATE.CHAP_STT = this.STATE.CHAP_STT_ORIGINAL = chap_stt || 1;
                this.STATE.CHAP_SERIAL = this.STATE.CHAP_SERIAL_ORIGINAL = chap_serial || 1;
            } catch (e) {
                console.error("Error initializing chapter values:", e);
            }
        },

        cacheElements: function() {
            this.ELEMENTS.qpContent = jQuery("#qpContent");
            this.ELEMENTS.qpButtonSubmit = jQuery("#qpButtonSubmit");
            this.ELEMENTS.qpButtonRemoveEmpty = jQuery("#qpButtonRemoveEmpty");
            this.ELEMENTS.qpButtonPaste = jQuery("#qpButtonPaste");
            this.ELEMENTS.qpButtonAutoPost = jQuery("#qpButtonAutoPost");
            this.ELEMENTS.qpButtonReset = jQuery("#qpButtonReset");
            this.ELEMENTS.qpOptionLoop = jQuery("#qpOptionLoop");
        },

        registerEvents: function() {
            this.ELEMENTS.qpContent.on("paste", this.handlePaste.bind(this));
            this.ELEMENTS.qpButtonRemoveEmpty.on('click', this.removeEmptyChapters.bind(this));
            this.ELEMENTS.qpButtonSubmit.on('click', this.submitChapters.bind(this));
            this.ELEMENTS.qpButtonPaste.on('click', this.handlePasteButton.bind(this));
            this.ELEMENTS.qpButtonAutoPost.on('click', this.toggleAutoPost.bind(this));
            this.ELEMENTS.qpButtonReset.on('click', this.resetAutoPost.bind(this));
            this.ELEMENTS.qpOptionLoop.on('change', this.toggleAutoMode.bind(this));
            setupCharacterCounter();

            // Kiểm tra và bắt đầu tự động đăng nếu đã bật
            if (window.location.href.includes('/dang-chuong/story/')) {
                setTimeout(() => {
                    if (this.STATE.AUTO_POST && this.STATE.POSTED_CHAPTERS < this.STATE.TOTAL_CHAPTERS) {
                        this.runAutoPostSequence();
                    }
                }, 2000);
            }
        },

        handlePasteButton: function() {
            this.showLoading();
            navigator.clipboard.readText()
                .then(text => {
                    this.ELEMENTS.qpContent.val(text);
                    setTimeout(() => {
                        this.performAction();
                        this.hideLoading();
                    }, 100);
                })
                .catch(err => {
                    console.error('Không thể đọc dữ liệu từ clipboard:', err);
                    this.hideLoading();
                    showNotification('Không thể truy cập clipboard. Vui lòng dán trực tiếp vào ô nội dung.', 'error');
                });
        },

        handlePaste: function(e) {
            e.preventDefault();
            this.ELEMENTS.qpContent.val("");
            this.showLoading();
            const pastedText = e.originalEvent.clipboardData.getData('text');
            this.ELEMENTS.qpContent.val(pastedText);
            setTimeout(() => {
                this.performAction();
                this.hideLoading();
            }, 100);
        },

        performAction: function() {
            try {
                console.log("Starting performAction");
                var text = this.ELEMENTS.qpContent.val();

                if (!text) {
                    showNotification('Không có nội dung để tách chương', 'error');
                    return 0;
                }
                var debugOutput = [];
                var chapters = [];
                var lines = text.split('\n');
                var currentChapter = [];
                var lastTitle = null;
                debugOutput.push("=== Processing Text ===");
                debugOutput.push(`Total lines: ${lines.length}`);
                debugOutput.push("=== Line Analysis ===");
                function visualizeWhitespace(str) {
                    return str.split('').map(c => {
                        if (c === '\t') return '\\t';
                        if (c === ' ') return '·';
                        if (c === '\n') return '\\n';
                        return c;
                    }).join('');
                }

                // Hàm lấy mã chương dựa vào tiêu đề
                function getChapterCode(title) {
                    // Lấy số chương + tên chương, bỏ qua các ký tự đặc biệt
                    const match = title.match(/[Cc]hương\s*(\d+)\s*:/);
                    if (!match) return title.trim();
                    const chapterNum = match[1];
                    return `chap_${chapterNum}`;
                }

                for (let i = 0; i < lines.length; i++) {
                    let line = lines[i];
                    let isChapterTitle = 
                        /^\t[Cc]hương\s*\d+\s*:/.test(line) || // tab + Chương + số:
                        /^\s{4,}[Cc]hương\s*\d+\s*:/.test(line) || // spaces + Chương + số:
                        /^\t[Cc]hương\s*\d+(?!\S)/.test(line) || // tab + Chương + số (không có dấu :)
                        /^\s{4,}[Cc]hương\s*\d+(?!\S)/.test(line) || // spaces + Chương + số (không có dấu :)
                        /^[Cc]hương\s*\d+\s*:/.test(line) || // Chương + số:
                        /^[Cc]hương\s*\d+(?!\S)/.test(line); // Chương + số (không có dấu :)
                    debugOutput.push(`Line ${i}: ${visualizeWhitespace(line.substring(0, 50))}${line.length > 50 ? '...' : ''}`);
                    debugOutput.push(`  Is chapter: ${isChapterTitle}`);

                    if (isChapterTitle) {
                        // Lấy mã chương để so sánh
                        const currentChapterCode = getChapterCode(line);
                        const lastTitleCode = lastTitle ? getChapterCode(lastTitle) : null;

                        if (currentChapter.length > 0) {
                            // Kiểm tra nếu chương hiện tại khác chương trước đó
                            if (currentChapterCode !== lastTitleCode) {
                                chapters.push(currentChapter.join('\n'));
                                currentChapter = [line];
                                lastTitle = line;
                                debugOutput.push(`  -> New chapter started: ${currentChapterCode}`);
                            } else {
                                debugOutput.push(`  -> Skipped duplicate chapter: ${currentChapterCode}`);
                                // Không cần thêm dòng này vào chapter hiện tại vì nó là tiêu đề trùng lặp
                            }
                        } else {
                            currentChapter = [line];
                            lastTitle = line;
                            debugOutput.push(`  -> First chapter started: ${currentChapterCode}`);
                        }
                    } else if (currentChapter.length > 0) {
                        currentChapter.push(line);
                    }
                }
                if (currentChapter.length > 0) {
                    chapters.push(currentChapter.join('\n'));
                    debugOutput.push("-> Added final chapter");
                }
                debugOutput.push("=== Results ===");
                debugOutput.push(`Found ${chapters.length} chapters`);
                const processedChapters = [];
                const MAX_CHAPTER_LENGTH = 40000;

                for (let i = 0; i < chapters.length; i++) {
                    const chapterLines = chapters[i].split('\n');
                    const title = chapterLines.shift().trim();
                    const chapterText = chapterLines.join('\n');

                    //                    // Check if title already has (Phần x/y) format
                    const partPattern = /\s*\(Phần\s+\d+\/\d+\)\s*$/i;
                    const baseTitle = title.replace(partPattern, '').trim();

                    // Check if chapter is too long
                    if (chapterText.length > MAX_CHAPTER_LENGTH) {
                        console.log(`[TTV-DEBUG] Chapter too long (${chapterText.length} chars), splitting...`);

                        try {
                            // Calculate how many parts we need
                            const numParts = Math.ceil(chapterText.length / MAX_CHAPTER_LENGTH);

                            // Split the chapter into multiple parts
                            for (let part = 0; part < numParts; part++) {
                                const startPos = part * MAX_CHAPTER_LENGTH;
                                let endPos = Math.min((part + 1) * MAX_CHAPTER_LENGTH, chapterText.length);

                                // Find a natural paragraph break if possible
                                if (part < numParts - 1) {  // Only for non-last parts
                                    const searchText = chapterText.substring(endPos - 1000, endPos + 1000);
                                    const paragraphBreak = searchText.indexOf('\n\n');

                                    if (paragraphBreak > 0 && paragraphBreak < 1000) {
                                        // Adjust end position to end at paragraph break
                                        endPos = endPos - 1000 + paragraphBreak;
                                    }
                                }

                                const partText = chapterText.substring(startPos, endPos);

                                // Add this part as a chapter
                                processedChapters.push({
                                    displayTitle: `${baseTitle} (Phần ${part + 1}/${numParts})`,
                                    originalTitle: baseTitle,
                                    displayContent: partText.trim(),
                                    clipboardContent: partText.trim(),
                                    length: partText.trim().length
                                });
                            }
                        } catch (err) {
                            console.error(`[TTV-ERROR] Error splitting chapter: ${err.message}`);
                            // If there's an error during splitting, add the whole chapter
                            processedChapters.push({
                                displayTitle: title,
                                originalTitle: title,
                                displayContent: chapterText,
                                clipboardContent: chapterText,
                                length: chapterText.length
                            });
                        }
                    } else {
                        // Chapter is not too long, add it as is
                        processedChapters.push({
                            displayTitle: title,
                            originalTitle: title,
                            displayContent: chapterText,
                            clipboardContent: chapterText,
                            length: chapterText.length
                        });
                    }
                }
                debugOutput.push(`After processing: ${processedChapters.length} chapters`);
                const chaptersToFill = processedChapters.slice(0, MAX_CHAPTER_POST);
                const remainingChapters = processedChapters.slice(MAX_CHAPTER_POST);
                var titles = jQuery("input[name^='chap_name']");
                var contents = jQuery("textarea[name^='introduce']");
                var advs = jQuery("textarea[name^='adv']");
                debugOutput.push(`Forms found: ${titles.length}`);
                if (processedChapters.length === 0) {
                    showNotification('Không tìm thấy chương nào', 'error');
                    jQuery('#debug-output').text(debugOutput.join('\n'));
                    return;
                }
                if (remainingChapters.length > 0) {
                    debugOutput.push(`${remainingChapters.length} chapters will be copied to clipboard`);
                }
                const neededForms = chaptersToFill.length - titles.length;
                if (neededForms > 0 && titles.length < MAX_CHAPTER_POST) {
                    debugOutput.push(`Need to add ${neededForms} more forms`);
                    for (let i = 0; i < neededForms && (titles.length + i) < MAX_CHAPTER_POST; i++) {
                        this.addNewChapter();
                    }
                    titles = jQuery("input[name^='chap_name']");
                    contents = jQuery("textarea[name^='introduce']");
                    advs = jQuery("textarea[name^='adv']");
                }
                debugOutput.push(`Filling ${chaptersToFill.length} chapters into forms`);
                jQuery.each(titles, function(k, v) {
                    if (k < chaptersToFill.length) {
                        var content = chaptersToFill[k].split('\n');
                        var title = content.shift().trim();

                        // Tìm định dạng "Chương + số:" hoặc "Chương + số"
                        var chapterMatch = title.match(/[Cc]hương\s*\d+(\s*:)?/);
                        var chapterTitle = "";

                        if (chapterMatch) {
                            // Lấy phần sau "Chương + số:" hoặc "Chương + số"
                            var matchedPart = chapterMatch[0];
                            if (matchedPart.endsWith(':')) {
                                // Nếu có dấu ":", lấy phần sau dấu ":"
                                chapterTitle = title.substring(title.indexOf(':') + 1).trim();
                            } else {
                                // Nếu không có dấu ":", lấy phần sau "Chương + số"
                                chapterTitle = title.substring(matchedPart.length).trim();
                            }

                            // Nếu không có nội dung sau "Chương + số", sử dụng "Vô đề"
                            if (!chapterTitle) {
                                chapterTitle = "Vô đề";
                            }
                        } else {
                            // Nếu không tìm thấy định dạng "Chương + số"
                            chapterTitle = title;
                        }

                        debugOutput.push(`\nFilling chapter ${k + 1}:`);
                        debugOutput.push(`Original title: ${title}`);
                        debugOutput.push(`Extracted title: ${chapterTitle}`);
                        debugOutput.push(`Content length: ${content.length} lines`);
                        if (!chapterTitle || chapterTitle.trim() === '') {
                            chapterTitle = "Vô đề";
                            debugOutput.push(`Empty title detected, using default: ${chapterTitle}`);
                        }
                        titles[k].value = chapterTitle;
                        contents[k].value = HEADER_SIGN + "\r\n" + content.join('\n') + "\r\n" + FOOTER_SIGN;
                        if (advs[k]) advs[k].value = "";
                        jQuery(contents[k]).trigger('input');
                    }
                });
                if (remainingChapters.length > 0) {
                    try {
                        const clipboardContent = remainingChapters.map(chap => {
                            const lines = chap.clipboardContent.trim().split('\n');
                            if (lines.length > 0) {
                                // Xử lý dòng đầu tiên để đảm bảo đúng định dạng
                                let firstLine = lines[0];

                                // Loại bỏ tab hoặc khoảng trắng ở đầu
                                firstLine = firstLine.replace(/^[\t\s]+/, '');

                                // Kiểm tra xem đã có định dạng Chương + số chưa
                                const chapterMatch = firstLine.match(/^([Cc]hương\s*\d+)/);
                                if (chapterMatch) {
                                    // Nếu không có dấu ":" thì thêm vào
                                    if (!firstLine.includes(':')) {
                                        firstLine = chapterMatch[0] + ': ' + firstLine.substring(chapterMatch[0].length).trim();
                                    }
                                }

                                // Thêm tab vào đầu
                                lines[0] = '\t' + firstLine;
                            }
                            return lines.join('\n');
                        }).join('\n\n');
                        let splitChapters = 0;
                        let shortChapters = 0;
                        let shortChapterDetails = [];
                        let longChapterDetails = [];
                        for (let i = 0; i < chapters.length; i++) {
                            const chapterLines = chapters[i].split('\n');
                            const title = chapterLines.shift().trim();
                            const chapterText = chapterLines.join('\n');
                            if (chapterText.length > 40000) {
                                splitChapters++;
                                const partsCount = Math.ceil(chapterText.length / 40000);
                                longChapterDetails.push({
                                    title: title,
                                    parts: partsCount
                                });
                            }
                            if (chapterText.length < 3000) {
                                shortChapters++;
                                shortChapterDetails.push({
                                    title: title,
                                    length: chapterText.length
                                });
                            }
                        }
                        const splittedChaptersCount = processedChapters.length - (chapters.length - splitChapters);
                        let message = '';
                        message = message.concat(`📝 Đã xử lý ${processedChapters.length} Chương\n`);
                        message = message.concat(`📝 Đã nhập ${Math.min(processedChapters.length, MAX_CHAPTER_POST)} Chương\n`);

                        if (remainingChapters.length > 0) {
                            message = message.concat(`📋 Đã lưu lại ${remainingChapters.length} Chương\n`);
                        }
                        if (splitChapters > 0) {
                            message = message.concat(`📑 Có ${splitChapters} Chương đã chia thành ${splittedChaptersCount} Chương\n`);
                            longChapterDetails.forEach(chapter => {
                                let chapterName = chapter.title;
                                if (chapterName.includes(':')) {
                                    chapterName = chapterName.trim();
                                }
                                message = message.concat(` - ${chapterName}: ${chapter.parts} Chương\n`);
                            });
                        }
                        if (shortChapters > 0) {
                            message = message.concat(`⚠️<span class="short-chapters-warning">Có ${shortChapters} chương dưới 3000 ký tự</span>\n`);
                            shortChapterDetails.forEach(chapter => {
                                let chapterName = chapter.title;
                                if (chapterName.includes(':')) {
                                    chapterName = chapterName.trim();
                                }
                                message = message.concat(`<span class="short-chapters-warning"> - ${chapterName}: có ${chapter.length.toLocaleString()} ký tự</span>\n`);
                            });
                        }
                        if (navigator.clipboard && navigator.clipboard.writeText) {
                            navigator.clipboard.writeText(clipboardContent)
                                .then(() => {
                                    debugOutput.push(`📋Đã lưu lại ${remainingChapters.length} Chương\n`);
                                    showNotification(message, remainingChapters.length > 0 ? 'warning' : 'success');
                                })
                                .catch(err => {
                                    throw err;
                                });
                        } else {
                            const tempTextarea = document.createElement('textarea');
                            tempTextarea.style.position = 'fixed';
                            tempTextarea.style.top = '0';
                            tempTextarea.style.left = '0';
                            tempTextarea.style.width = '2em';
                            tempTextarea.style.height = '2em';
                            tempTextarea.style.opacity = '0';
                            tempTextarea.style.pointerEvents = 'none';
                            tempTextarea.value = clipboardContent;
                            document.body.appendChild(tempTextarea);
                            tempTextarea.focus();
                            tempTextarea.select();
                            const successful = document.execCommand('copy');
                            document.body.removeChild(tempTextarea);
                            if (!successful) {
                                throw new Error('Không thể sao chép vào clipboard');
                            }
                            debugOutput.push(`Đã sao chép ${remainingChapters.length} chương vào clipboard (execCommand)`);
                            showNotification(message, 'success');
                        }
                    } catch (err) {
                        console.error('Lỗi khi sao chép vào clipboard:', err);
                        debugOutput.push(`Lỗi khi sao chép vào clipboard: ${err.message}`);
                        showNotification('Không thể sao chép vào clipboard. Vui lòng thử lại.', 'error');
                        const manualCopyArea = document.createElement('div');
                        manualCopyArea.style.position = 'fixed';
                        manualCopyArea.style.top = '50%';
                        manualCopyArea.style.left = '50%';
                        manualCopyArea.style.transform = 'translate(-50%, -50%)';
                        manualCopyArea.style.backgroundColor = 'white';
                        manualCopyArea.style.padding = '20px';
                        manualCopyArea.style.borderRadius = '8px';
                        manualCopyArea.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
                        manualCopyArea.style.zIndex = '10000';
                        manualCopyArea.style.maxWidth = '80%';
                        manualCopyArea.style.maxHeight = '80%';
                        manualCopyArea.style.overflow = 'auto';
                        manualCopyArea.innerHTML = `
                            <h3 style="margin-top: 0;">Sao chép thủ công</h3>
                            <p>Không thể sao chép tự động. Vui lòng chọn toàn bộ nội dung bên dưới và sao chép (Ctrl+C):</p>
                            <textarea style="width: 100%; height: 300px; padding: 10px;">${clipboardContent}</textarea>
                            <div style="text-align: right; margin-top: 10px;">
                                <button id="closeManualCopy" style="padding: 8px 16px; background: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer;">Đóng</button>
                            </div>
                        `;
                        document.body.appendChild(manualCopyArea);
                        document.getElementById('closeManualCopy').addEventListener('click', () => {
                            document.body.removeChild(manualCopyArea);
                        });
                    }
                }
                this.ELEMENTS.qpButtonSubmit.removeClass("btn-disable").addClass("btn-success");
                this.ELEMENTS.qpContent.val("Đã xử lý xong");
                if (remainingChapters.length === 0) {
                    let splitChapters = 0;
                    let shortChapters = 0;
                    let shortChapterDetails = [];
                    let longChapterDetails = [];
                    for (let i = 0; i < chapters.length; i++) {
                        const chapterLines = chapters[i].split('\n');
                        const title = chapterLines.shift().trim();
                        const chapterText = chapterLines.join('\n');
                        if (chapterText.length > 40000) {
                            splitChapters++;
                            const partsCount = Math.ceil(chapterText.length / 40000);
                            longChapterDetails.push({
                                title: title,
                                parts: partsCount
                            });
                        }
                        if (chapterText.length < 3000) {
                            shortChapters++;
                            shortChapterDetails.push({
                                title: title,
                                length: chapterText.length
                            });
                        }
                    }
                    const splittedChaptersCount = processedChapters.length - (chapters.length - splitChapters);
                    let message = '';
                    message = message.concat(`📝 Đã xử lý ${processedChapters.length} Chương\n`);
                    message = message.concat(`📝 Đã nhập ${Math.min(processedChapters.length, MAX_CHAPTER_POST)} Chương\n`);
                    if (splitChapters > 0) {
                        message = message.concat(`📑 Có ${splitChapters} Chương dài chia thành ${splittedChaptersCount} Chương\n`);
                        longChapterDetails.forEach(chapter => {
                            let chapterName = chapter.title;
                            if (chapterName.includes(':')) {
                                chapterName = chapterName.trim();
                            }
                            message = message.concat(` - ${chapterName}: ${chapter.parts} Chương\n`);
                        });
                    }
                    if (shortChapters > 0) {
                        message = message.concat(`⚠️<span class="short-chapters-warning">Có ${shortChapters} chương dưới 3000 ký tự</span>\n`);
                        shortChapterDetails.forEach(chapter => {
                            let chapterName = chapter.title;
                            if (chapterName.includes(':')) {
                                chapterName = chapterName.trim();
                            }
                            message = message.concat(`<span class="short-chapters-warning"> - ${chapterName}: có ${chapter.length.toLocaleString()} ký tự</span>\n`);
                        });
                    }
                    showNotification(message, 'success');
                }
                jQuery('#debug-output').text(debugOutput.join('\n'));
                return processedChapters.length;
            } catch (e) {
                console.error("Error in performAction:", e);
                showNotification('Có lỗi khi tách chương', 'error');
                return 0;
            }
        },

        removeEmptyChapters: function() {
            const forms = document.querySelectorAll('[data-gen="MK_GEN"]');
            let removed = 0;

            forms.forEach(form => {
                const content = form.querySelector('textarea[name^="introduce"]').value.trim();
                if (!content) {
                    form.remove();
                    removed++;
                    this.updateChapNumber(false);
                }
            });
            showNotification(`🧹 Đã xử lý ${forms.length} chương, xóa ${removed} chương trống`, 'info');
        },

        toggleAutoPost: function() {
            this.STATE.AUTO_POST = !this.STATE.AUTO_POST;

            if (this.STATE.AUTO_POST) {
                // Lưu trạng thái tự động đăng vào localStorage
                localStorage.setItem('TTV_AUTO_POST', 'true');
                this.STATE.TOTAL_CHAPTERS = parseInt(prompt("Nhập tổng số lần tự động đăng:", "10")) || 0;
                this.STATE.POSTED_CHAPTERS = parseInt(localStorage.getItem('TTV_POSTED_CHAPTERS') || '0');

                localStorage.setItem('TTV_TOTAL_CHAPTERS', this.STATE.TOTAL_CHAPTERS.toString());

                this.ELEMENTS.qpButtonAutoPost.text(`🔄 TỰ ĐỘNG (${this.STATE.POSTED_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS})`);
                this.ELEMENTS.qpButtonAutoPost.removeClass('btn-warning').addClass('btn-info');

                showNotification(`✅ Đã bật tự động đăng (${this.STATE.POSTED_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS})`, 'success');

                // Bắt đầu quy trình tự động
                if (window.location.href.includes('/dang-chuong/story/')) {
                    setTimeout(() => this.runAutoPostSequence(), 2000);
                }
            } else {
                // Tắt tự động đăng
                localStorage.setItem('TTV_AUTO_POST', 'false');
                // Reset số lần đã đăng về 0
                this.STATE.POSTED_CHAPTERS = 0;
                localStorage.setItem('TTV_POSTED_CHAPTERS', '0');
                // Reset tổng số lần đăng về 0
                this.STATE.TOTAL_CHAPTERS = 0;
                localStorage.setItem('TTV_TOTAL_CHAPTERS', '0');
                this.ELEMENTS.qpButtonAutoPost.text('🔄 TỰ ĐỘNG (TẮT)');
                this.ELEMENTS.qpButtonAutoPost.removeClass('btn-info').addClass('btn-warning');
                showNotification('❌ Đã tắt tự động đăng và reset số lần đăng', 'info');
            }
        },

        runAutoPostSequence: function() {
            // Kiểm tra trước khi chạy tự động
            if (this.STATE.POSTED_CHAPTERS >= this.STATE.TOTAL_CHAPTERS) {
                // Reset trạng thái tự động nếu đã hoàn thành
                this.STATE.AUTO_POST = false;
                localStorage.setItem('TTV_AUTO_POST', 'false');
                this.ELEMENTS.qpButtonAutoPost.text('🔄 TỰ ĐỘNG (TẮT)');
                this.ELEMENTS.qpButtonAutoPost.removeClass('btn-info').addClass('btn-warning');

                // Reset số lần đã đăng
                this.STATE.POSTED_CHAPTERS = 0;
                localStorage.setItem('TTV_POSTED_CHAPTERS', '0');

                showNotification(`🎉 Đã hoàn thành tự động đăng ${this.STATE.TOTAL_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS} chương và đã reset số lần đăng`, 'success');
                return;
            }

            if (!this.STATE.AUTO_POST) {
                return;
            }

            // Tự động nhấn nút Paste sau 2 giây
            setTimeout(() => {
                if (this.STATE.AUTO_POST) {
                    this.handlePasteButton();

                    // Tự động nhấn nút Đăng chương sau 3 giây
                    setTimeout(() => {
                        if (this.STATE.AUTO_POST) {
                            this.submitChapters();
                        }
                    }, 3000);
                }
            }, 2000);
        },

        submitChapters: function() {
            if (!validateChapterLengths()) {
                showNotification('⚠️ Có chương có độ dài dưới 3000 ký tự. Vui lòng kiểm tra lại.', 'error');
                return;
            }
            this.showLoading();
            document.querySelector('form[name="postChapForm"] button[type="submit"]').click();

            if (this.STATE.AUTO_POST) {
                // Cập nhật số chương đã đăng
                this.STATE.POSTED_CHAPTERS++;
                localStorage.setItem('TTV_POSTED_CHAPTERS', this.STATE.POSTED_CHAPTERS.toString());

                // Kiểm tra và tắt tự động đăng nếu đã đủ số chương
                if (this.STATE.POSTED_CHAPTERS >= this.STATE.TOTAL_CHAPTERS) {
                    this.STATE.AUTO_POST = false;
                    localStorage.setItem('TTV_AUTO_POST', 'false');
                    this.ELEMENTS.qpButtonAutoPost.text('🔄 TỰ ĐỘNG (TẮT)');
                    this.ELEMENTS.qpButtonAutoPost.removeClass('btn-info').addClass('btn-warning');

                    // Reset số lần đã đăng
                    this.STATE.POSTED_CHAPTERS = 0;
                    localStorage.setItem('TTV_POSTED_CHAPTERS', '0');

                    setTimeout(() => {
                        showNotification(`🎉 Đã hoàn thành tự động đăng ${this.STATE.TOTAL_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS} chương và đã reset số lần đăng`, 'success');
                    }, 3000);
                } else {
                    // Cập nhật hiển thị số chương đã đăng
                    this.ELEMENTS.qpButtonAutoPost.text(`🔄 TỰ ĐỘNG (${this.STATE.POSTED_CHAPTERS}/${this.STATE.TOTAL_CHAPTERS})`);
                }
            }

            setTimeout(() => this.hideLoading(), 2000);
        },

        addNewChapter: function() {
            if ((this.STATE.CHAP_NUMBER + 1) <= MAX_CHAPTER_POST) {
                this.updateChapNumber(true);
                const html = createChapterHTML(this.STATE.CHAP_NUMBER);
                jQuery('#add-chap').before(html);
                setupCharacterCounter();
            } else {
                showNotification(`⚠️ Chỉ có thể đăng tối đa ${MAX_CHAPTER_POST} chương một lần`, 'warning');
            }
        },

        updateChapNumber: function(isAdd) {
            try{
                if (isAdd) {
                    let maxStt = 0;
                    let maxSerial = 0;
                    jQuery('input[name^="chap_stt"]').each(function() {
                        const val = parseInt(jQuery(this).val()) || 0;
                        maxStt = Math.max(maxStt, val);
                    });
                    jQuery('input[name^="chap_number"]').each(function() {
                        const val = parseInt(jQuery(this).val()) || 0;
                        maxSerial = Math.max(maxSerial, val);
                    });
                    const chapStt = parseInt(jQuery('.chap_stt1').val()) || 0;
                    const chapSerial = parseInt(jQuery('.chap_serial').val()) || 0;
                    maxStt = Math.max(maxStt, chapStt);
                    maxSerial = Math.max(maxSerial, chapSerial);
                    this.STATE.CHAP_STT = maxStt + 1;
                    this.STATE.CHAP_SERIAL = maxSerial + 1;
                    this.STATE.CHAP_NUMBER++;
                } else {
                    if (this.STATE.CHAP_NUMBER > this.STATE.CHAP_NUMBER_ORIGINAL) {
                        this.STATE.CHAP_NUMBER--;
                    }
                    if (this.STATE.CHAP_STT > this.STATE.CHAP_STT_ORIGINAL) {
                        this.STATE.CHAP_STT--;
                    }
                    if (this.STATE.CHAP_SERIAL > this.STATE.CHAP_SERIAL_ORIGINAL) {
                        this.STATE.CHAP_SERIAL--;
                    }
                }
                jQuery('#chap_number').val(this.STATE.CHAP_NUMBER);
                jQuery('#chap_stt').val(this.STATE.CHAP_STT);
                jQuery('#chap_serial').val(this.STATE.CHAP_SERIAL);
                jQuery('#countNumberPost').text(this.STATE.CHAP_NUMBER);
            } catch (e) {
                console.log("Lỗi: " + e);
            }
        },

        showLoading: function() {
            const loading = jQuery("<div>", {
                class: "loading-overlay",
                html: "<div class='loading-spinner'></div>"
            });
            jQuery("body").append(loading);
        },

        hideLoading: function() {
            jQuery(".loading-overlay").remove();
        },

        resetAutoPost: function() {
            this.STATE.TOTAL_CHAPTERS = 0;
            this.STATE.POSTED_CHAPTERS = 0;
            localStorage.removeItem('TTV_TOTAL_CHAPTERS');
            localStorage.removeItem('TTV_POSTED_CHAPTERS');
            this.ELEMENTS.qpButtonAutoPost.text('🔄 TỰ ĐỘNG (TẮT)');
            this.ELEMENTS.qpButtonAutoPost.removeClass('btn-info').addClass('btn-warning');
            showNotification('🔄 Đã reset số lần tự động đăng', 'info');
        },

        toggleAutoMode: function() {
            const isAutoMode = this.ELEMENTS.qpOptionLoop.is(':checked');

            if (isAutoMode) {
                // Hiển thị nút tự động đăng và reset, ẩn nút paste và đăng chương
                this.ELEMENTS.qpButtonAutoPost.show();
                this.ELEMENTS.qpButtonReset.show();
                this.ELEMENTS.qpButtonPaste.hide();
                this.ELEMENTS.qpButtonSubmit.hide();

                showNotification('🔄 Đã bật chế độ tự động', 'info');
            } else {
                // Hiển thị nút paste và đăng chương, ẩn nút tự động đăng và reset
                this.ELEMENTS.qpButtonAutoPost.hide();
                this.ELEMENTS.qpButtonReset.hide();
                this.ELEMENTS.qpButtonPaste.show();
                this.ELEMENTS.qpButtonSubmit.show();

                showNotification('❌ Đã tắt chế độ tự động', 'info');
            }

            // Lưu trạng thái vào localStorage
            localStorage.setItem('TTV_AUTO_MODE', isAutoMode.toString());
        }
    };
    dangNhanhTTV.init();
})();