Chapter Downloader

Tự động lấy nội dung từ chương hiện tại đến chương cuối cùng trên truyen.tangthuvien.vn

当前为 2025-04-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Chapter Downloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.0
  5. // @description Tự động lấy nội dung từ chương hiện tại đến chương cuối cùng trên truyen.tangthuvien.vn
  6. // @author You
  7. // @match https://truyen.tangthuvien.vn/doc-truyen/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. let chapterUrls = [];
  15. let currentChapterIndex = 0;
  16. let isAutoDownloading = false;
  17.  
  18. const panel = document.createElement('div');
  19. panel.id = 'reader-panel';
  20. panel.style.cssText = `
  21. position: fixed;
  22. top: 10%;
  23. right: 10px;
  24. width: 300px;
  25. background-color: #f8f8f8;
  26. border: 1px solid #ccc;
  27. border-radius: 5px;
  28. padding: 10px;
  29. z-index: 9999;
  30. box-shadow: 0 0 10px rgba(0,0,0,0.2);
  31. font-family: Arial, sans-serif;
  32. `;
  33.  
  34. const textarea = document.createElement('textarea');
  35. textarea.id = 'content-textarea';
  36. textarea.style.cssText = `
  37. width: 100%;
  38. height: 300px;
  39. margin-bottom: 10px;
  40. padding: 8px;
  41. border: 1px solid #ddd;
  42. border-radius: 4px;
  43. resize: vertical;
  44. `;
  45.  
  46. const startButton = document.createElement('button');
  47. startButton.textContent = 'Bắt đầu';
  48. startButton.style.cssText = `
  49. width: 100%;
  50. padding: 8px;
  51. margin-bottom: 10px;
  52. background-color: #4CAF50;
  53. color: white;
  54. border: none;
  55. border-radius: 4px;
  56. cursor: pointer;
  57. `;
  58.  
  59. const buttonRow1 = document.createElement('div');
  60. buttonRow1.style.cssText = `display: flex; justify-content: space-between; margin-bottom: 10px;`;
  61.  
  62. const getTextButton = document.createElement('button');
  63. getTextButton.textContent = 'Lấy Text';
  64. getTextButton.style.cssText = `
  65. flex: 1;
  66. padding: 8px;
  67. margin-right: 5px;
  68. background-color: #2196F3;
  69. color: white;
  70. border: none;
  71. border-radius: 4px;
  72. cursor: pointer;
  73. `;
  74.  
  75. const nextChapterButton = document.createElement('button');
  76. nextChapterButton.textContent = 'Chương Tiếp';
  77. nextChapterButton.style.cssText = `
  78. flex: 1;
  79. padding: 8px;
  80. margin-left: 5px;
  81. background-color: #ff9800;
  82. color: white;
  83. border: none;
  84. border-radius: 4px;
  85. cursor: pointer;
  86. `;
  87.  
  88. const buttonRow2 = document.createElement('div');
  89. buttonRow2.style.cssText = `display: flex; justify-content: space-between;`;
  90.  
  91. const clearButton = document.createElement('button');
  92. clearButton.textContent = 'Xoá';
  93. clearButton.style.cssText = `
  94. flex: 1;
  95. padding: 8px;
  96. margin-right: 5px;
  97. background-color: #f44336;
  98. color: white;
  99. border: none;
  100. border-radius: 4px;
  101. cursor: pointer;
  102. `;
  103.  
  104. const copyButton = document.createElement('button');
  105. copyButton.textContent = 'Sao Chép';
  106. copyButton.style.cssText = `
  107. flex: 1;
  108. padding: 8px;
  109. margin-left: 5px;
  110. background-color: #9c27b0;
  111. color: white;
  112. border: none;
  113. border-radius: 4px;
  114. cursor: pointer;
  115. `;
  116.  
  117. buttonRow1.appendChild(getTextButton);
  118. buttonRow1.appendChild(nextChapterButton);
  119. buttonRow2.appendChild(clearButton);
  120. buttonRow2.appendChild(copyButton);
  121. panel.appendChild(textarea);
  122. panel.appendChild(startButton);
  123. panel.appendChild(buttonRow1);
  124. panel.appendChild(buttonRow2);
  125.  
  126. const shortcutsInfo = document.createElement('div');
  127. shortcutsInfo.style.cssText = `font-size: 11px; color: #666; margin-top: 10px; padding-top: 5px; border-top: 1px solid #ddd;`;
  128. shortcutsInfo.innerHTML = `<b>Phím tt:</b> Alt+G (Ly text), Alt+N (Chương tiếp), Alt+S (T động), Alt+C (Sao chép)`;
  129. panel.appendChild(shortcutsInfo);
  130. document.body.appendChild(panel);
  131.  
  132. const savedContent = localStorage.getItem('chapterDownloaderContent');
  133. if (savedContent) {
  134. textarea.value = savedContent;
  135. }
  136.  
  137. function saveContent() {
  138. localStorage.setItem('chapterDownloaderContent', textarea.value);
  139. }
  140.  
  141. textarea.addEventListener('input', saveContent);
  142.  
  143. function extractChapterContent() {
  144. const titleElement = document.querySelector('h2');
  145. const contentElement = document.querySelector('.box-chap');
  146.  
  147. if (titleElement && contentElement) {
  148. const title = titleElement.innerText.trim();
  149. const content = contentElement.innerText.trim();
  150.  
  151. if (textarea.value) {
  152. textarea.value += '\n\n------------\n\n' + title + '\n\n' + content;
  153. } else {
  154. textarea.value = title + '\n\n' + content;
  155. }
  156.  
  157. saveContent();
  158. return true;
  159. } else {
  160. return false;
  161. }
  162. }
  163.  
  164. function startAutoDownloading() {
  165. if (!isAutoDownloading) return;
  166.  
  167. if (chapterUrls.length === 0) {
  168. const allLinks = Array.from(document.querySelectorAll('a[href*="/doc-truyen/"]'));
  169. const filteredLinks = allLinks.map(a => a.href).filter((href, index, self) => href.includes('chuong') && self.indexOf(href) === index);
  170. chapterUrls = filteredLinks;
  171.  
  172. const currentUrl = window.location.href.split('?')[0];
  173. currentChapterIndex = chapterUrls.findIndex(url => url === currentUrl);
  174.  
  175. if (currentChapterIndex === -1) {
  176. console.log('Không tìm thấy chương hiện tại trong danh sách!');
  177. isAutoDownloading = false;
  178. return;
  179. }
  180. }
  181.  
  182. if (currentChapterIndex < chapterUrls.length) {
  183. const currentUrl = chapterUrls[currentChapterIndex];
  184. console.log(`Đang ti chương ${currentChapterIndex + 1}/${chapterUrls.length}: ${currentUrl}`);
  185.  
  186. if (window.location.href !== currentUrl) {
  187. window.location.href = currentUrl;
  188. return;
  189. }
  190.  
  191. if (extractChapterContent()) {
  192. currentChapterIndex++;
  193. setTimeout(startAutoDownloading, 2000);
  194. } else {
  195. console.log('Không lấy được nội dung chương, dừng lại.');
  196. isAutoDownloading = false;
  197. }
  198. } else {
  199. console.log('Đã tải xong tất cả chương!');
  200. isAutoDownloading = false;
  201. startButton.textContent = 'Bắt đầu';
  202. startButton.style.backgroundColor = '#4CAF50';
  203. }
  204. }
  205.  
  206. startButton.addEventListener('click', () => {
  207. isAutoDownloading = !isAutoDownloading;
  208. if (isAutoDownloading) {
  209. startButton.textContent = 'Dừng';
  210. startButton.style.backgroundColor = '#f44336';
  211. startAutoDownloading();
  212. } else {
  213. startButton.textContent = 'Bắt đầu';
  214. startButton.style.backgroundColor = '#4CAF50';
  215. }
  216. });
  217.  
  218. getTextButton.addEventListener('click', () => extractChapterContent());
  219. nextChapterButton.addEventListener('click', () => {
  220. const nextLink = document.querySelector('.bot-next_chap.bot-control');
  221. if (nextLink) nextLink.click();
  222. });
  223. clearButton.addEventListener('click', () => {
  224. textarea.value = '';
  225. saveContent();
  226. });
  227. copyButton.addEventListener('click', () => {
  228. textarea.select();
  229. document.execCommand('copy');
  230.  
  231. const notification = document.createElement('div');
  232. notification.textContent = 'Đã sao chép!';
  233. notification.style.cssText = `
  234. position: fixed;
  235. bottom: 20px;
  236. left: 50%;
  237. transform: translateX(-50%);
  238. background-color: rgba(0,0,0,0.8);
  239. color: white;
  240. padding: 10px 20px;
  241. border-radius: 4px;
  242. z-index: 10000;
  243. `;
  244. document.body.appendChild(notification);
  245. setTimeout(() => document.body.removeChild(notification), 2000);
  246. });
  247.  
  248. document.addEventListener('keydown', (e) => {
  249. if (e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'INPUT') {
  250. if (e.altKey && e.key === 'g') {
  251. extractChapterContent();
  252. e.preventDefault();
  253. } else if (e.altKey && e.key === 'n') {
  254. const nextLink = document.querySelector('.bot-next_chap.bot-control');
  255. if (nextLink) nextLink.click();
  256. e.preventDefault();
  257. } else if (e.altKey && e.key === 's') {
  258. startButton.click();
  259. e.preventDefault();
  260. } else if (e.altKey && e.key === 'c') {
  261. textarea.select();
  262. document.execCommand('copy');
  263. e.preventDefault();
  264. }
  265. }
  266. });
  267. })();