TTV Auto Upload

Tự động điền form đăng chương trên tangthuvien.net với tính năng nâng cao

目前為 2025-03-08 提交的版本,檢視 最新版本

// ==UserScript==
// @name         TTV Auto Upload
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Tự động điền form đăng chương trên tangthuvien.net với tính năng nâng cao
// @author       HA
// @match        https://tangthuvien.net/dang-chuong/story/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Thêm CSS cho thông báo và nút
    const style = document.createElement('style');
    style.textContent = `
        .ttv-notification {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 10px 20px;
            background: #4CAF50;
            color: white;
            border-radius: 4px;
            z-index: 9999;
            display: none;
        }
        .ttv-error {
            background: #f44336;
        }
        .ttv-control-panel {
            position: fixed;
            top: 50px;
            right: 20px;
            background: white;
            padding: 15px;
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
            z-index: 9998;
            width: 400px;
            margin-bottom: 20px;
            transition: all 0.3s ease;
        }

        .ttv-control-panel.minimized {
            width: auto;
            height: auto;
            padding: 10px;
            opacity: 0.8;
            transform: translateX(calc(100% - 40px));
            transition: all 0.3s ease;
        }

        .ttv-control-panel.minimized:hover {
            opacity: 1;
            transform: translateX(0);
        }

        .ttv-control-panel.minimized .ttv-button-group,
        .ttv-control-panel.minimized .ttv-header {
            display: none;
        }

        // Điều chỉnh toolbar và các nút điều khiển
        .ttv-toolbar {
            display: flex;
            gap: 6px;
            align-items: center;
        }

        .ttv-toolbar button {
            padding: 3px 10px;
            font-size: 12px;
            color: #555;
            background: #f5f5f5;
            border: 1px solid #ddd;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .ttv-toolbar button:hover {
            background: #e9e9e9;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .ttv-button-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        .ttv-file-label {
            width: 100%;
            padding: 8px;
            background: #5bc0de;
            color: white;
            border-radius: 6px;
            cursor: pointer;
            font-size: 13px;
            text-align: center;
            transition: all 0.2s ease;
            margin: 0;
        }

        .ttv-file-label:hover {
            background: #46b8da;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .ttv-content-editor {
            width: 100%;
            height: 300px;
            margin: 8px 0;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 8px;
            font-size: 14px;
            line-height: 1.6;
            resize: vertical;
            transition: all 0.2s ease;
        }

        .ttv-content-editor:focus {
            border-color: #5bc0de;
            outline: none;
            box-shadow: 0 0 8px rgba(91,192,222,0.2);
        }

        .ttv-preview {
            display: none;
            width: 100%;
            height: 300px;
            margin: 8px 0;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 8px;
            font-size: 14px;
            line-height: 1.6;
            overflow-y: auto;
            background: #f9f9f9;
            transition: all 0.2s ease;
        }
        .ttv-heading {
            font-size: 12px;
            color: #555;
            margin: 8px 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .ttv-word-count {
            font-size: 11px;
            color: #888;
            padding: 3px 6px;
            background: #f5f5f5;
            border-radius: 4px;
            transition: all 0.2s ease;
        }
        // Tối ưu chế độ toàn màn hình
        .ttv-control-panel.fullscreen {
            position: fixed;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 100%;
            border-radius: 0;
            z-index: 9999;
            padding: 20px;
            display: flex;
            flex-direction: column;
        }

        .ttv-control-panel.fullscreen .ttv-content-editor,
        .ttv-control-panel.fullscreen .ttv-preview {
            height: calc(100vh - 200px);
            margin: 12px 0;
            font-size: 15px;
        }
        .ttv-header {
            margin-bottom: 15px;
            padding-bottom: 12px;
            border-bottom: 2px solid #eee;
            font-weight: bold;
            font-size: 14px;
            color: #444;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        button.btn-warning {
            background: #f0ad4e;
            color: white;
            border: none;
            padding: 8px;
            border-radius: 6px;
            width: 100%;
            font-size: 13px;
            transition: all 0.2s ease;
        }
        button.btn-warning:hover {
            background: #ec971f;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        button.ttv-minimize {
            padding: 2px 8px;
            background: none;
            border: none;
            cursor: pointer;
            font-size: 16px;
            color: #666;
            transition: all 0.2s ease;
        }

        button.ttv-minimize:hover {
            color: #333;
        }
    `;
    document.head.appendChild(style);

    // Tạo div thông báo
    const notification = document.createElement('div');
    notification.className = 'ttv-notification';
    document.body.appendChild(notification);

    // Hiển thị thông báo
    function showNotification(message, isError = false) {
        notification.textContent = message;
        notification.className = 'ttv-notification' + (isError ? ' ttv-error' : '');
        notification.style.display = 'block';
        setTimeout(() => {
            notification.style.display = 'none';
        }, 3000);
    }

    // Đọc nội dung file
    function readFileContent(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = (e) => resolve(e.target.result);
            reader.onerror = (e) => reject(new Error('Lỗi đọc file: ' + e.target.error));
            reader.readAsText(file, 'UTF-8');
        });
    }

    // Đếm số từ và ký tự
    function updateWordCount(content) {
        const wordCount = content.trim().split(/\s+/).length;
        const charCount = content.length;
        return `${wordCount} từ | ${charCount} ký tự`;
    }


    // Xử lý khi chọn file
    async function handleFileSelect(event) {
        try {
            const file = event.target.files[0];
            if (!file) return;

            // Đọc nội dung file
            const content = await readFileContent(file);

            // Điền vào khung soạn thảo nội dung
            const contentEditor = document.querySelector('.ttv-content-editor');
            if (contentEditor) {
                contentEditor.value = content;

                // Cập nhật số từ
                const wordCountSpan = document.querySelector('.ttv-word-count');
                if (wordCountSpan) {
                    wordCountSpan.textContent = updateWordCount(content);
                }

                showNotification('Đã tải nội dung từ file thành công!');
            } else {
                showNotification('Không tìm thấy khung soạn thảo!', true);
            }
        } catch (error) {
            console.error('Lỗi xử lý file:', error);
            showNotification('Có lỗi xảy ra khi đọc file!', true);
        }
    }

    // Chuyển nội dung từ khung soạn thảo sang form
    function transferContent() {
        const contentEditor = document.querySelector('.ttv-content-editor');
        const contentInput = document.querySelector('textarea[name="introduce[1]"]');

        if (contentEditor && contentInput) {
            contentInput.value = contentEditor.value;
            showNotification('Đã chuyển nội dung sang form đăng chương!');
        } else {
            showNotification('Không tìm thấy form đăng chương!', true);
        }
    }

    // Chuyển đổi giữa chế độ soạn thảo và xem trước
    function togglePreview() {
        const contentEditor = document.querySelector('.ttv-content-editor');
        const preview = document.querySelector('.ttv-preview');
        const previewBtn = document.querySelector('.ttv-preview-btn');

        if (contentEditor.style.display !== 'none') {
            contentEditor.style.display = 'none';
            preview.style.display = 'block';
            preview.innerHTML = contentEditor.value.replace(/\n/g, '<br>');
            previewBtn.textContent = 'Soạn thảo';
        } else {
            contentEditor.style.display = 'block';
            preview.style.display = 'none';
            previewBtn.textContent = 'Xem trước';
        }
    }

    // Chuyển đổi chế độ toàn màn hình
    function toggleFullscreen() {
        const panel = document.querySelector('.ttv-control-panel');
        const fullscreenBtn = document.querySelector('.ttv-fullscreen-btn');

        panel.classList.toggle('fullscreen');
        fullscreenBtn.textContent = panel.classList.contains('fullscreen') ? 'Thu nhỏ' : 'Toàn màn hình';
    }

    // Thêm panel điều khiển
    function addControlPanel() {
        // Tạo panel
        const panel = document.createElement('div');
        panel.className = 'ttv-control-panel';

        // Thêm header
        const header = document.createElement('div');
        header.className = 'ttv-header';
        header.innerHTML = `
            <div>Soạn Thảo Nội Dung</div>
            <div class="ttv-toolbar">
                <button class="ttv-preview-btn" onclick="togglePreview()">Xem trước</button>
                <button class="ttv-fullscreen-btn" onclick="toggleFullscreen()">Toàn màn hình</button>
                <button class="ttv-minimize">−</button>
            </div>
        `;

        // Container cho các nút
        const buttonGroup = document.createElement('div');
        buttonGroup.className = 'ttv-button-group';

        // Input chọn file
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.txt';
        fileInput.className = 'ttv-file-input';
        fileInput.id = 'ttv-file-input';
        fileInput.onchange = handleFileSelect;

        // Label cho input file
        const fileLabel = document.createElement('label');
        fileLabel.htmlFor = 'ttv-file-input';
        fileLabel.className = 'ttv-file-label';
        fileLabel.innerHTML = '<span>Chọn file txt chứa nội dung</span>';

        // Khung soạn thảo nội dung
        const contentEditorLabel = document.createElement('div');
        contentEditorLabel.className = 'ttv-heading';
        contentEditorLabel.innerHTML = `
            Nội dung chương:
            <span class="ttv-word-count">0 từ | 0 ký tự</span>
        `;

        const contentEditor = document.createElement('textarea');
        contentEditor.className = 'ttv-content-editor';
        contentEditor.placeholder = 'Nhập hoặc dán nội dung chương vào đây...';

        // Khung xem trước
        const preview = document.createElement('div');
        preview.className = 'ttv-preview';

        // Cập nhật số từ khi nhập nội dung
        contentEditor.oninput = () => {
            const wordCountSpan = document.querySelector('.ttv-word-count');
            if (wordCountSpan) {
                wordCountSpan.textContent = updateWordCount(contentEditor.value);
            }
        };

        // Nút chuyển nội dung
        const transferBtn = document.createElement('button');
        transferBtn.type = 'button';
        transferBtn.className = 'btn btn-warning';
        transferBtn.innerHTML = '<span>Chuyển nội dung sang form</span>';
        transferBtn.onclick = transferContent;

        // Thêm các phần tử vào panel
        panel.appendChild(header);
        buttonGroup.appendChild(fileInput);
        buttonGroup.appendChild(fileLabel);
        buttonGroup.appendChild(contentEditorLabel);
        buttonGroup.appendChild(contentEditor);
        buttonGroup.appendChild(preview);
        buttonGroup.appendChild(transferBtn);
        panel.appendChild(buttonGroup);

        document.body.appendChild(panel);

        // Thêm xử lý sự kiện cho các nút trong toolbar
        const minimizeBtn = panel.querySelector('.ttv-minimize');
        minimizeBtn.onclick = () => {
            panel.classList.toggle('minimized');
            minimizeBtn.innerHTML = panel.classList.contains('minimized') ? '+' : '−';
        };

        window.togglePreview = togglePreview;
        window.toggleFullscreen = toggleFullscreen;
    }

    // Thêm control panel khi trang đã load
    window.addEventListener('load', function() {
        addControlPanel();
    });
})();