Chapter Downloader

Tải nội dung chương truyện từ TangThuVien

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

// ==UserScript==
// @name         Chapter Downloader 
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Tải nội dung chương truyện từ TangThuVien
// @author       Your name
// @match        https://truyen.tangthuvien.net/doc-truyen/*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // Thêm CSS cho khung soạn thảo
    GM_addStyle(`
        .story-editor-container {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 400px;
            height: 80vh;
            background: white;
            border: 1px solid #ccc;
            padding: 10px;
            z-index: 9999;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .story-editor {
            flex: 1;
            width: 100%;
            resize: none;
            font-family: Arial, sans-serif;
            font-size: 14px;
            line-height: 1.6;
            padding: 10px;
        }
        .button-container {
            display: flex;
            gap: 10px;
        }
        button {
            padding: 8px 16px;
            cursor: pointer;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
        }
        button:hover {
            background: #45a049;
        }
        .status-text {
            font-size: 12px;
            color: #666;
        }
    `);

    // Lấy nội dung chương hiện tại
    function getCurrentChapter() {
        try {
            console.log('Bắt đầu lấy nội dung chương...');

            // Tìm container chứa nội dung
            const container = document.querySelector('#article') || document.querySelector('.content-chapter');
            if (!container) {
                throw new Error('Không tìm thấy container chương');
            }

            // Tìm tiêu đề với nhiều selector
            const titleSelectors = [
                '.chapter-title',
                'h2.chapter-title',
                '.chapter-c h2',
                'h2',
                '.content-chapter h2'
            ];

            let titleElement = null;
            for (const selector of titleSelectors) {
                const element = container.querySelector(selector);
                if (element && element.textContent.trim()) {
                    titleElement = element;
                    console.log('Tìm thấy tiêu đề với selector:', selector);
                    break;
                }
            }

            // Tìm nội dung với nhiều selector
            const contentSelectors = [
                '.chapter-c',
                '.chapter-content',
                '.content-chapter'
            ];

            let contentElement = null;
            for (const selector of contentSelectors) {
                const element = container.querySelector(selector);
                if (element && element.textContent.trim()) {
                    contentElement = element;
                    console.log('Tìm thấy nội dung với selector:', selector);
                    break;
                }
            }

            console.log('Elements tìm thấy:', {
                hasTitle: !!titleElement,
                hasContent: !!contentElement,
                titleHTML: titleElement?.outerHTML,
                contentPreview: contentElement?.textContent?.trim().substring(0, 100)
            });

            if (!titleElement || !contentElement) {
                throw new Error('Không tìm thấy nội dung chương');
            }

            // Lấy và làm sạch nội dung
            let title = titleElement.textContent.trim();
            let content = contentElement.textContent.trim();

            // Loại bỏ các phần thừa
            content = content.replace(title, ''); // Xóa tiêu đề nếu trùng
            content = content.replace(/\[\s*\w+\s*\]/g, ''); // Xóa [xxx]
            content = content.replace(/[""]/g, '"'); // Chuẩn hóa dấu ngoặc kép
            content = content.replace(/\s+/g, ' '); // Chuẩn hóa khoảng trắng
            content = content.replace(/^\s+|\s+$/g, ''); // Trim

            if (!title || !content) {
                throw new Error('Nội dung chương không hợp lệ');
            }

            console.log('Đã lấy nội dung:', {
                title,
                contentLength: content.length,
                contentPreview: content.substring(0, 100) + '...'
            });

            return { title, content };
        } catch (error) {
            console.error('Lỗi khi lấy nội dung chương:', error);
            updateStatus('Lỗi khi lấy nội dung chương: ' + error.message);
            return null;
        }
    }

    // Tạo UI elements
    function createUI() {
        console.log('Tạo giao diện...');

        const container = document.createElement('div');
        container.className = 'story-editor-container';

        const editor = document.createElement('textarea');
        editor.className = 'story-editor';
        editor.placeholder = 'Nội dung truyện sẽ hiển thị ở đây...';
        editor.readOnly = true;

        const buttonContainer = document.createElement('div');
        buttonContainer.className = 'button-container';

        const downloadBtn = document.createElement('button');
        downloadBtn.textContent = 'Tải chương tiếp';
        downloadBtn.onclick = loadNextChapter;

        const exportBtn = document.createElement('button');
        exportBtn.textContent = 'Xuất file TXT';
        exportBtn.onclick = exportToTxt;

        buttonContainer.appendChild(downloadBtn);
        buttonContainer.appendChild(exportBtn);

        const status = document.createElement('div');
        status.className = 'status-text';

        container.appendChild(editor);
        container.appendChild(buttonContainer);
        container.appendChild(status);
        document.body.appendChild(container);

        console.log('Đã tạo giao diện thành công');
        return { editor, downloadBtn, exportBtn, status };
    }

    // Cập nhật trạng thái
    function updateStatus(message) {
        const status = document.querySelector('.status-text');
        if (status) {
            status.textContent = message;
            console.log('Trạng thái:', message);
        }
    }

    // Thêm nội dung chương mới vào editor
    function appendChapterContent(editor, title, content) {
        try {
            console.log('Bắt đầu thêm nội dung chương mới');
            console.log('Nội dung hiện tại:', editor.value.length, 'ký tự');

            // Thêm dấu phân cách nếu đã có nội dung
            const separator = editor.value ? '\n\n' + '-'.repeat(50) + '\n\n' : '';
            const newContent = title + '\n\n' + content;

            // Thêm nội dung mới và giữ lại nội dung cũ
            editor.value = editor.value + separator + newContent;

            // Cuộn xuống dưới để hiển thị nội dung mới
            editor.scrollTop = editor.scrollHeight;

            console.log('Đã thêm thành công:', {
                addedLength: newContent.length,
                currentLength: editor.value.length
            });
            return true;
        } catch (error) {
            console.error('Lỗi khi thêm nội dung:', error);
            return false;
        }
    }

    // Xuất nội dung ra file txt
    function exportToTxt() {
        try {
            console.log('Bắt đầu xuất file...');
            const editor = document.querySelector('.story-editor');
            if (!editor || !editor.value) {
                throw new Error('Không có nội dung để xuất');
            }

            const blob = new Blob([editor.value], { type: 'text/plain;charset=utf-8' });
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');

            // Lấy tên truyện từ URL
            const storyName = window.location.pathname.split('/')[2] || 'truyen';

            link.href = url;
            link.download = `${storyName}.txt`;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            window.URL.revokeObjectURL(url);

            updateStatus('Đã xuất file thành công!');
            console.log('Xuất file hoàn tất');
        } catch (error) {
            console.error('Lỗi khi xuất file:', error);
            updateStatus('Lỗi khi xuất file: ' + error.message);
        }
    }

    // Chuyển đến chương tiếp theo
    function goToNextChapter() {
        const nextButton = document.querySelector('a.next-chap');
        if (nextButton && !nextButton.classList.contains('disabled') && nextButton.style.display !== 'none') {
            console.log('Nhấn nút chuyển chương tiếp theo');
            nextButton.click();
            return true;
        }
        console.log('Không tìm thấy nút chuyển chương hợp lệ');
        return false;
    }

    // Kiểm tra xem có phải chương cuối không
    function isLastChapter() {
        const nextButton = document.querySelector('a.next-chap');
        console.log('Kiểm tra chương cuối:', {
            buttonExists: !!nextButton,
            isDisabled: nextButton?.classList.contains('disabled'),
            isHidden: nextButton?.style.display === 'none'
        });
        return !nextButton || nextButton.classList.contains('disabled') || nextButton.style.display === 'none';
    }

    // Tải chương tiếp theo
    async function loadNextChapter() {
        try {
            console.log('Bắt đầu tải chương tiếp');
            updateStatus('Đang tải chương tiếp theo...');

            const editor = document.querySelector('.story-editor');
            if (!editor) {
                throw new Error('Không tìm thấy khung soạn thảo');
            }

            // Đợi 5 giây để nội dung được tải
            await new Promise(resolve => setTimeout(resolve, 5000));

            // Lấy nội dung chương hiện tại
            const currentChapter = getCurrentChapter();
            if (!currentChapter) {
                throw new Error('Không thể lấy nội dung chương hiện tại');
            }

            const { title, content } = currentChapter;

            // Thêm nội dung mới vào cuối
            appendChapterContent(editor, title, content);
            updateStatus('Đã tải xong chương hiện tại');

            // Kiểm tra nếu là chương cuối
            if (isLastChapter()) {
                console.log('Đã phát hiện chương cuối');
                updateStatus('Đã tải xong tất cả các chương! Đang xuất file...');
                setTimeout(exportToTxt, 1000);
                return;
            }

            // Chuyển sang chương tiếp theo sau khi lấy xong chương hiện tại
            setTimeout(() => {
                if (goToNextChapter()) {
                    setTimeout(loadNextChapter, 3000);
                }
            }, 1000);
        } catch (error) {
            console.error('Lỗi khi tải chương:', error);
            updateStatus('Lỗi khi tải chương: ' + error.message);
        }
    }

    // Khởi tạo khi DOM đã sẵn sàng
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createUI);
    } else {
        createUI();
    }

    console.log('TangThuVien Chapter Downloader đã khởi chạy');
})();