Chapter Downloader

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

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Chapter Downloader 
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Tải nội dung chương truyện từ TangThuVien
// @author       Your name
// @match        https://truyen.tangthuvien.net/doc-truyen/*/*
// @match        https://truyen.tangthuvien.vn/doc-truyen/*/*
// @match        https://tangthuvien.vn/doc-truyen/*/*
// @match        https://tangthuvien.com/doc-truyen/*/*
// @match        https://*.tangthuvien.*/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;
        }
    `);

    // Log tất cả các elements có thể chứa nội dung
    function logPossibleElements() {
        const elements = document.querySelectorAll('*');
        const contentElements = Array.from(elements).filter(el => {
            const text = el.textContent?.trim();
            return text && text.length > 100;
        });

        console.log('Các elements có thể chứa nội dung:', 
            contentElements.map(el => ({
                tagName: el.tagName,
                className: el.className,
                id: el.id,
                textLength: el.textContent?.trim().length,
                firstChars: el.textContent?.trim().substring(0, 50)
            }))
        );
    }

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

            // Đợi nội dung tải xong (tăng thời gian chờ lên 5 giây)
            console.log('Đợi 5 giây để nội dung tải hoàn tất...');
            await new Promise(resolve => setTimeout(resolve, 5000));

            // Tìm container chính - mở rộng bộ chọn để phù hợp với TangThuVien
            const mainContainer = document.querySelector('#article') || 
                                document.querySelector('.content-chapter') || 
                                document.querySelector('.chapter-content') ||
                                document.querySelector('.box-chap') ||
                                document.querySelector('.content') ||
                                document.querySelector('.chapter');

            console.log('Container chính:', {
                found: !!mainContainer,
                id: mainContainer?.id,
                className: mainContainer?.className
            });

            // Nếu không tìm thấy container chính, thử tìm trực tiếp trong document
            // TangThuVien có thể không tuân theo cấu trúc container>tiêu đề+nội dung
            if (!mainContainer) {
                console.log('Không tìm thấy container chính, thử tìm trực tiếp trong document');
            }

            // Tìm tiêu đề
            const titleSelectors = [
                'h2.chapter-title',
                '.chapter-title',
                '.truyen-title',
                'h2.title',
                '.content-chapter h2',
                '.chapter h1',
                '.title-chapter',
                '.chapter-title h2',
                'h1.title',
                'header h1'
            ];

            let titleElement;
            // Tìm trong container chính nếu có
            if (mainContainer) {
                for (const selector of titleSelectors) {
                    titleElement = mainContainer.querySelector(selector);
                    if (titleElement?.textContent?.trim()) {
                        console.log('Tìm thấy tiêu đề với selector trong container:', selector);
                        break;
                    }
                }
            }
            
            // Nếu không tìm thấy trong container, tìm trong toàn bộ document
            if (!titleElement || !titleElement?.textContent?.trim()) {
                for (const selector of titleSelectors) {
                    titleElement = document.querySelector(selector);
                    if (titleElement?.textContent?.trim()) {
                        console.log('Tìm thấy tiêu đề với selector trong document:', selector);
                        break;
                    }
                }
            }

            // Tìm nội dung
            const contentSelectors = [
                '.chapter-c',
                '.chapter-content',
                '.content-chapter',
                '.box-chap',
                '.content',
                '#content',
                '.chapter-detail',
                '.chapter-text',
                '.chapter__content',
                '.ttv-chapter-content'
            ];

            let contentElement;
            // Tìm trong container chính nếu có
            if (mainContainer) {
                for (const selector of contentSelectors) {
                    contentElement = mainContainer.querySelector(selector);
                    if (contentElement?.textContent?.trim()) {
                        console.log('Tìm thấy nội dung với selector trong container:', selector);
                        break;
                    }
                }
            }
            
            // Nếu không tìm thấy trong container, tìm trong toàn bộ document
            if (!contentElement || !contentElement?.textContent?.trim()) {
                for (const selector of contentSelectors) {
                    contentElement = document.querySelector(selector);
                    if (contentElement?.textContent?.trim()) {
                        console.log('Tìm thấy nội dung với selector trong document:', selector);
                        break;
                    }
                }
            }

            // Xử lý trường hợp không tìm thấy tiêu đề hoặc nội dung
            if (!titleElement && !contentElement) {
                console.error('Không tìm thấy cả tiêu đề và nội dung');
                // Thử phương pháp cuối cùng - lấy toàn bộ văn bản của trang
                const bodyText = document.body.innerText;
                if (bodyText && bodyText.length > 500) { // Giả sử trang có ít nhất 500 ký tự
                    console.log('Thử phương pháp cuối cùng - lấy toàn bộ văn bản');
                    
                    // Lấy tiêu đề từ thẻ title của trang
                    const pageTitle = document.title.trim();
                    
                    return {
                        title: pageTitle,
                        content: bodyText
                    };
                }
                throw new Error('Không tìm thấy nội dung hoặc tiêu đề');
            }
            
            if (!titleElement) {
                console.log('Không tìm thấy tiêu đề, sử dụng title của trang');
                const pageTitle = document.title.trim();
                titleElement = { textContent: pageTitle };
            }
            
            if (!contentElement) {
                console.error('Không tìm thấy nội dung:', {
                    hasTitle: !!titleElement,
                    titleHTML: titleElement?.outerHTML
                });
                throw new Error('Không tìm thấy nội dung');
            }

            console.log('Tìm thấy cả tiêu đề và nội dung:', {
                hasTitle: !!titleElement,
                hasContent: !!contentElement,
                titlePreview: titleElement?.textContent?.trim().substring(0, 50),
                contentPreview: contentElement?.textContent?.trim().substring(0, 100)
            });

            // Xử lý nội dung
            let title = titleElement.textContent.trim();
            let content = contentElement.textContent.trim();

            // Làm sạch nội dung
            content = content.replace(title, ''); // Xóa tiêu đề khỏi nội dung
            content = content.replace(/\[\s*\w+\s*\]/g, ''); // Xóa [xxx]
            content = content.replace(/\[.*?\]/g, ''); // Xóa tất cả nội dung trong ngoặc vuông
            content = content.replace(/[""]/g, '"'); // Chuẩn hóa dấu ngoặc kép
            content = content.replace(/\s+/g, ' ').trim(); // Chuẩn hóa khoảng trắng
            
            // Loại bỏ các đoạn quảng cáo phổ biến
            content = content.replace(/Truyện\s+VIP\s+\S+/gi, '');
            content = content.replace(/Đọc\s+truyện\s+tại\s+\S+/gi, '');
            content = content.replace(/Tham\s+gia\s+group\s+\S+/gi, '');
            content = content.replace(/nguồn\s*:\s*\S+/gi, '');

            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:', error);
            return null;
        }
    }

    // Thêm nội dung chương mới vào editor
    function appendChapterContent(editor, title, content) {
        try {
            if (!editor || !title || !content) {
                console.error('Input không hợp lệ:', {
                    hasEditor: !!editor,
                    hasTitle: !!title,
                    hasContent: !!content
                });
                return false;
            }

            // 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;

            // Nối tiếp nội dung vào cuối
            editor.value += separator + newContent;
            editor.scrollTop = editor.scrollHeight;

            console.log('Đã thêm nội dung:', {
                previousLength: editor.value.length - (separator + newContent).length,
                addedLength: newContent.length,
                newTotalLength: editor.value.length
            });

            return true;
        } catch (error) {
            console.error('Lỗi khi thêm nội dung:', error);
            return false;
        }
    }

    // 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('Chuyển đến chương tiếp theo');
            nextButton.click();
            return true;
        }
        console.log('Không tìm thấy nút next hợp lệ');
        return false;
    }

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

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

            // Đợi nội dung tải
            const chapterData = await getCurrentChapter();
            if (!chapterData) {
                throw new Error('Không lấy được nội dung chương');
            }

            // Thêm nội dung vào editor
            if (!appendChapterContent(editor, chapterData.title, chapterData.content)) {
                throw new Error('Không thêm được nội dung vào editor');
            }

            // Tự động tải chương tiếp
            setTimeout(() => {
                if (goToNextChapter()) {
                    setTimeout(loadNextChapter, 3000);
                }
            }, 1000);

        } catch (error) {
            console.error('Lỗi khi tải chương:', error);
        }
    }

    // Xuất nội dung ra file txt
    function exportToTxt() {
        try {
            const editor = document.querySelector('.story-editor');
            if (!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');

            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);

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

    // Tạo giao diện
    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);

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

        console.log('Đã tạo giao diện thành công');
    }

    // Khởi tạo script
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createUI);
    } else {
        createUI();
    }

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