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