您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add a control panel for novel reading on truyen.tangthuvien.net
当前为
- // ==UserScript==
- // @name Chapter Downloader
- // @namespace http://tampermonkey.net/
- // @version 2.1
- // @description Add a control panel for novel reading on truyen.tangthuvien.net
- // @author You
- // @match https://truyen.tangthuvien.net/doc-truyen/*
- // @match https://truyen.tangthuvien.net/doc-truyen/*/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- // Create panel container
- const panel = document.createElement('div');
- panel.id = 'reader-panel';
- panel.style.cssText = `
- position: fixed;
- top: 10%;
- right: 10px;
- width: 300px;
- background-color: #f8f8f8;
- border: 1px solid #ccc;
- border-radius: 5px;
- padding: 10px;
- z-index: 9999;
- box-shadow: 0 0 10px rgba(0,0,0,0.2);
- font-family: Arial, sans-serif;
- `;
- // Create textarea
- const textarea = document.createElement('textarea');
- textarea.id = 'content-textarea';
- textarea.style.cssText = `
- width: 100%;
- height: 300px;
- margin-bottom: 10px;
- padding: 8px;
- border: 1px solid #ddd;
- border-radius: 4px;
- resize: vertical;
- `;
- // Create start button
- const startButton = document.createElement('button');
- startButton.textContent = 'Bắt đầu';
- startButton.style.cssText = `
- width: 100%;
- padding: 8px;
- margin-bottom: 10px;
- background-color: #4CAF50;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- `;
- // Create container for getTextButton and nextChapterButton (same row)
- const buttonRow1 = document.createElement('div');
- buttonRow1.style.cssText = `
- display: flex;
- justify-content: space-between;
- margin-bottom: 10px;
- `;
- // Create get text button
- const getTextButton = document.createElement('button');
- getTextButton.textContent = 'Lấy Text';
- getTextButton.style.cssText = `
- flex: 1;
- padding: 8px;
- margin-right: 5px;
- background-color: #2196F3;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- `;
- // Create next chapter button
- const nextChapterButton = document.createElement('button');
- nextChapterButton.textContent = 'Chương Tiếp';
- nextChapterButton.style.cssText = `
- flex: 1;
- padding: 8px;
- margin-left: 5px;
- background-color: #ff9800;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- `;
- // Create container for clearButton and copyButton (same row)
- const buttonRow2 = document.createElement('div');
- buttonRow2.style.cssText = `
- display: flex;
- justify-content: space-between;
- `;
- // Create clear button
- const clearButton = document.createElement('button');
- clearButton.textContent = 'Xoá';
- clearButton.style.cssText = `
- flex: 1;
- padding: 8px;
- margin-right: 5px;
- background-color: #f44336;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- `;
- // Create copy button
- const copyButton = document.createElement('button');
- copyButton.textContent = 'Sao Chép';
- copyButton.style.cssText = `
- flex: 1;
- padding: 8px;
- margin-left: 5px;
- background-color: #9c27b0;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- `;
- // Add buttons to their respective row containers
- buttonRow1.appendChild(getTextButton);
- buttonRow1.appendChild(nextChapterButton);
- buttonRow2.appendChild(clearButton);
- buttonRow2.appendChild(copyButton);
- // Add all elements to panel
- panel.appendChild(textarea);
- panel.appendChild(startButton);
- panel.appendChild(buttonRow1);
- panel.appendChild(buttonRow2);
- // Add panel to body
- document.body.appendChild(panel);
- // Load saved content from localStorage if exists
- const savedContent = localStorage.getItem('chapterDownloaderContent');
- if (savedContent) {
- textarea.value = savedContent;
- }
- // Function to save content to localStorage
- function saveContent() {
- localStorage.setItem('chapterDownloaderContent', textarea.value);
- console.log('Content saved to localStorage');
- }
- // Auto save when textarea value changes
- textarea.addEventListener('input', saveContent);
- // Function to extract and add chapter content
- function extractChapterContent() {
- // Get chapter title
- const titleElement = document.querySelector('h2');
- // Get chapter content
- const contentElement = document.querySelector('.box-chap');
- if (titleElement && contentElement) {
- // Append to existing content rather than replacing
- const title = titleElement.innerText.trim();
- const content = contentElement.innerText.trim();
- // Append with proper formatting
- if (textarea.value) {
- textarea.value += '\n\n------------\n\n' + title + '\n\n' + content;
- } else {
- textarea.value = title + '\n\n' + content;
- }
- // Save content after adding new chapter
- saveContent();
- return true;
- } else {
- console.log('Could not find title or content elements');
- return false;
- }
- }
- // Function to navigate to next chapter
- function goToNextChapter() {
- // Find the next chapter button with the correct selector
- const nextChapterLink = document.querySelector('.bot-next_chap.bot-control');
- if (nextChapterLink) {
- console.log('Found next chapter link, navigating...');
- nextChapterLink.click();
- return true;
- } else {
- console.log('Could not find next chapter link with class ".bot-next_chap.bot-control"');
- // Try alternative selectors if the main one doesn't work
- const alternativeNextLinks = document.querySelectorAll('a[href*="chuong"]');
- for (const link of alternativeNextLinks) {
- if (link.textContent.includes('tiếp') || link.textContent.includes('sau') || link.textContent.includes('next')) {
- console.log('Found alternative next chapter link, navigating...');
- link.click();
- return true;
- }
- }
- return false;
- }
- }
- // Variable to track auto-downloading state
- let isAutoDownloading = false;
- // Function to handle automatic downloading
- function startAutoDownloading() {
- if (!isAutoDownloading) return;
- console.log('Auto-downloading: Extracting chapter content...');
- if (extractChapterContent()) {
- // After extracting, wait 1 second then navigate to next chapter
- setTimeout(() => {
- if (!isAutoDownloading) return;
- console.log('Auto-downloading: Navigating to next chapter...');
- if (goToNextChapter()) {
- // After navigation, wait 2 seconds for page to load then extract again
- setTimeout(() => {
- if (isAutoDownloading) {
- startAutoDownloading();
- }
- }, 2000); // Wait 2 seconds for page to load before extracting next chapter
- } else {
- console.log('Auto-downloading: Could not find next chapter, stopping.');
- isAutoDownloading = false;
- startButton.textContent = 'Bắt đầu';
- startButton.style.backgroundColor = '#4CAF50';
- }
- }, 1000); // Wait 1 second before navigating
- } else {
- console.log('Auto-downloading: Could not extract chapter content, stopping.');
- isAutoDownloading = false;
- startButton.textContent = 'Bắt đầu';
- startButton.style.backgroundColor = '#4CAF50';
- }
- }
- // Add event listeners
- startButton.addEventListener('click', () => {
- // Toggle auto-downloading state
- isAutoDownloading = !isAutoDownloading;
- if (isAutoDownloading) {
- console.log('Start button clicked: Beginning auto-download sequence');
- startButton.textContent = 'Dừng';
- startButton.style.backgroundColor = '#f44336'; // Red color to indicate active
- startAutoDownloading(); // Start the sequence
- } else {
- console.log('Start button clicked: Stopping auto-download sequence');
- startButton.textContent = 'Bắt đầu';
- startButton.style.backgroundColor = '#4CAF50'; // Green color when inactive
- }
- });
- getTextButton.addEventListener('click', () => {
- console.log('Get text button clicked');
- extractChapterContent();
- });
- nextChapterButton.addEventListener('click', () => {
- console.log('Next chapter button clicked');
- goToNextChapter();
- });
- clearButton.addEventListener('click', () => {
- console.log('Clear button clicked');
- textarea.value = '';
- saveContent(); // Save empty content to localStorage
- });
- copyButton.addEventListener('click', () => {
- console.log('Copy button clicked');
- textarea.select();
- document.execCommand('copy');
- // Show a temporary copy notification
- const notification = document.createElement('div');
- notification.textContent = 'Đã sao chép!';
- notification.style.cssText = `
- position: fixed;
- bottom: 20px;
- left: 50%;
- transform: translateX(-50%);
- background-color: rgba(0,0,0,0.8);
- color: white;
- padding: 10px 20px;
- border-radius: 4px;
- z-index: 10000;
- `;
- document.body.appendChild(notification);
- // Remove notification after 2 seconds
- setTimeout(() => {
- document.body.removeChild(notification);
- }, 2000);
- });
- // Make panel draggable
- let isDragging = false;
- let offsetX, offsetY;
- panel.addEventListener('mousedown', (e) => {
- if (e.target === panel) {
- isDragging = true;
- offsetX = e.clientX - panel.getBoundingClientRect().left;
- offsetY = e.clientY - panel.getBoundingClientRect().top;
- }
- });
- document.addEventListener('mousemove', (e) => {
- if (isDragging) {
- panel.style.left = (e.clientX - offsetX) + 'px';
- panel.style.top = (e.clientY - offsetY) + 'px';
- panel.style.right = 'auto';
- }
- });
- document.addEventListener('mouseup', () => {
- isDragging = false;
- });
- // Add keyboard shortcuts
- document.addEventListener('keydown', (e) => {
- // Only handle if not typing in a text field
- if (e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'INPUT') {
- // Alt+G: Get text
- if (e.altKey && e.key === 'g') {
- extractChapterContent();
- e.preventDefault();
- }
- // Alt+N: Next chapter
- else if (e.altKey && e.key === 'n') {
- goToNextChapter();
- e.preventDefault();
- }
- // Alt+S: Toggle auto-downloading (same as clicking Start/Stop button)
- else if (e.altKey && e.key === 's') {
- // Simulate clicking the start button
- startButton.click();
- e.preventDefault();
- }
- // Alt+C: Copy text
- else if (e.altKey && e.key === 'c') {
- textarea.select();
- document.execCommand('copy');
- e.preventDefault();
- }
- }
- });
- // Add information about keyboard shortcuts
- const shortcutsInfo = document.createElement('div');
- shortcutsInfo.style.cssText = `
- font-size: 11px;
- color: #666;
- margin-top: 10px;
- padding-top: 5px;
- border-top: 1px solid #ddd;
- `;
- shortcutsInfo.innerHTML = `
- <b>Phím tắt:</b> Alt+G (Lấy text), Alt+N (Chương tiếp), Alt+S (Bắt đầu/Dừng tự động), Alt+C (Sao chép)
- `;
- panel.appendChild(shortcutsInfo);
- console.log('Chapter Downloader script initialized successfully');
- })();