Chapter Downloader

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Chapter Downloader 
// @namespace    http://tampermonkey.net/
// @version      0.2
// @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;
        }
    `);

    // 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
            await new Promise(resolve => setTimeout(resolve, 3000));

            // Tìm container chính
            const mainContainer = document.querySelector('#article') || 
                                document.querySelector('.content-chapter') ||
                                document.querySelector('.chapter-content');

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

            if (!mainContainer) {
                throw new Error('Không tìm thấy container chính');
            }

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

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

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

            let contentElement;
            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:', selector);
                    break;
                }
            }

            if (!titleElement || !contentElement) {
                console.error('Không tìm thấy nội dung:', {
                    hasTitle: !!titleElement,
                    hasContent: !!contentElement,
                    titleHTML: titleElement?.outerHTML,
                    contentPreview: contentElement?.textContent?.trim().substring(0, 100)
                });
                throw new Error('Không tìm thấy nội dung hoặc tiêu đề');
            }

            // 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, '"'); // Chuẩn hóa dấu ngoặc kép
            content = content.replace(/\s+/g, ' ').trim(); // Chuẩn hóa khoảng trắng

            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');
})();