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