Chapter Downloader

Extract content from truyen.tangthuvien.net

当前为 2025-03-09 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Chapter Downloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.7
  5. // @description Extract content from truyen.tangthuvien.net
  6. // @author You
  7. // @match https://truyen.tangthuvien.net/doc-truyen/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Create container for extracted content
  15. function createContainer() {
  16. // Check if container already exists
  17. if (document.getElementById('content-extractor')) {
  18. return;
  19. }
  20.  
  21. const container = document.createElement('div');
  22. container.id = 'content-extractor';
  23. container.style.position = 'fixed';
  24. container.style.top = '0';
  25. container.style.right = '0';
  26. container.style.bottom = '0';
  27. container.style.width = '300px';
  28. container.style.backgroundColor = '#f5f5f5';
  29. container.style.padding = '15px';
  30. container.style.zIndex = '9999';
  31. container.style.boxShadow = '-2px 0 10px rgba(0,0,0,0.1)';
  32. container.style.overflow = 'auto';
  33.  
  34. const title = document.createElement('h3');
  35. title.textContent = 'Nội dung truyện đã trích xuất';
  36. title.style.marginTop = '0';
  37. container.appendChild(title);
  38.  
  39. const textarea = document.createElement('textarea');
  40. textarea.id = 'extracted-content';
  41. textarea.style.width = '100%';
  42. textarea.style.height = '150px';
  43. textarea.style.marginBottom = '10px';
  44. textarea.style.padding = '10px';
  45. textarea.style.boxSizing = 'border-box';
  46. // Load saved content if available
  47. const savedContent = localStorage.getItem('extractedNovelContent');
  48. if (savedContent) {
  49. textarea.value = savedContent;
  50. }
  51. // Auto-save content when it changes
  52. textarea.addEventListener('input', () => {
  53. localStorage.setItem('extractedNovelContent', textarea.value);
  54. });
  55. container.appendChild(textarea);
  56.  
  57. const buttonContainer = document.createElement('div');
  58. buttonContainer.style.display = 'flex';
  59. buttonContainer.style.flexDirection = 'column';
  60. buttonContainer.style.gap = '10px';
  61.  
  62. // Tạo nút "Bắt đầu lấy text"
  63. const startButton = document.createElement('button');
  64. startButton.textContent = 'Bắt đầu lấy text';
  65. startButton.style.padding = '10px 15px';
  66. startButton.style.backgroundColor = '#9c27b0';
  67. startButton.style.color = 'white';
  68. startButton.style.border = 'none';
  69. startButton.style.borderRadius = '4px';
  70. startButton.style.cursor = 'pointer';
  71. startButton.style.fontWeight = 'bold';
  72. // Thêm biến để kiểm soát quá trình tự động
  73. let isAutomaticExtraction = false;
  74. // Hàm đệ quy để tự động trích xuất và chuyển chương
  75. function autoExtractAndNavigate() {
  76. if (!isAutomaticExtraction) return;
  77. // Trích xuất nội dung chương hiện tại
  78. extractContent();
  79. // Tìm nút chuyển đến chương tiếp theo
  80. const nextButton = document.querySelector('.bot-next_chap.bot-control');
  81. if (nextButton) {
  82. // Hiển thị thông báo
  83. const notification = document.createElement('div');
  84. notification.textContent = 'Đã lấy xong chương hiện tại, đang chuyển đến chương kế tiếp...';
  85. notification.style.position = 'fixed';
  86. notification.style.bottom = '20px';
  87. notification.style.right = '320px';
  88. notification.style.backgroundColor = '#2196f3';
  89. notification.style.color = 'white';
  90. notification.style.padding = '10px';
  91. notification.style.borderRadius = '5px';
  92. notification.style.zIndex = '10000';
  93. document.body.appendChild(notification);
  94. // Xóa thông báo sau 2 giây
  95. setTimeout(() => {
  96. document.body.removeChild(notification);
  97. }, 2000);
  98. // Click vào nút chuyển chương
  99. nextButton.click();
  100. // Đợi trang mới tải xong rồi tiếp tục quy trình
  101. setTimeout(() => {
  102. autoExtractAndNavigate();
  103. }, 3000); // Đợi 3 giây cho trang tải xong
  104. } else {
  105. // Kết thúc quá trình khi không còn chương tiếp theo
  106. isAutomaticExtraction = false;
  107. startButton.textContent = 'Bắt đầu lấy text';
  108. startButton.style.display = 'block';
  109. // Hiển thị thông báo hoàn thành
  110. const notification = document.createElement('div');
  111. notification.textContent = 'Đã hoàn thành trích xuất toàn bộ truyện!';
  112. notification.style.position = 'fixed';
  113. notification.style.bottom = '20px';
  114. notification.style.right = '320px';
  115. notification.style.backgroundColor = '#4caf50';
  116. notification.style.color = 'white';
  117. notification.style.padding = '10px';
  118. notification.style.borderRadius = '5px';
  119. notification.style.zIndex = '10000';
  120. document.body.appendChild(notification);
  121. // Xóa thông báo sau 5 giây
  122. setTimeout(() => {
  123. document.body.removeChild(notification);
  124. }, 5000);
  125. }
  126. }
  127. // Thêm sự kiện khi click vào nút bắt đầu
  128. startButton.addEventListener('click', function() {
  129. if (!isAutomaticExtraction) {
  130. // Bắt đầu quá trình tự động
  131. isAutomaticExtraction = true;
  132. startButton.textContent = 'Dừng trích xuất';
  133. // Hiển thị thông báo đã bắt đầu
  134. const notification = document.createElement('div');
  135. notification.textContent = 'Đã bắt đầu tự động trích xuất nội dung';
  136. notification.style.position = 'fixed';
  137. notification.style.bottom = '20px';
  138. notification.style.right = '320px';
  139. notification.style.backgroundColor = '#9c27b0';
  140. notification.style.color = 'white';
  141. notification.style.padding = '10px';
  142. notification.style.borderRadius = '5px';
  143. notification.style.zIndex = '10000';
  144. document.body.appendChild(notification);
  145. // Xóa thông báo sau 3 giây
  146. setTimeout(() => {
  147. document.body.removeChild(notification);
  148. }, 3000);
  149. // Bắt đầu quá trình tự động
  150. autoExtractAndNavigate();
  151. } else {
  152. // Dừng quá trình tự động
  153. isAutomaticExtraction = false;
  154. startButton.textContent = 'Bắt đầu lấy text';
  155. // Hiển thị thông báo đã dừng
  156. const notification = document.createElement('div');
  157. notification.textContent = 'Đã dừng quá trình tự động trích xuất';
  158. notification.style.position = 'fixed';
  159. notification.style.bottom = '20px';
  160. notification.style.right = '320px';
  161. notification.style.backgroundColor = '#f44336';
  162. notification.style.color = 'white';
  163. notification.style.padding = '10px';
  164. notification.style.borderRadius = '5px';
  165. notification.style.zIndex = '10000';
  166. document.body.appendChild(notification);
  167. // Xóa thông báo sau 3 giây
  168. setTimeout(() => {
  169. document.body.removeChild(notification);
  170. }, 3000);
  171. }
  172. });
  173. buttonContainer.appendChild(startButton);
  174.  
  175. // Tạo các nút nhưng ẩn đi
  176. const extractButton = document.createElement('button');
  177. extractButton.textContent = 'Trích xuất nội dung trang hiện tại';
  178. extractButton.style.padding = '8px 15px';
  179. extractButton.style.backgroundColor = '#4caf50';
  180. extractButton.style.color = 'white';
  181. extractButton.style.border = 'none';
  182. extractButton.style.borderRadius = '4px';
  183. extractButton.style.cursor = 'pointer';
  184. extractButton.style.display = 'none'; // Ẩn nút
  185. extractButton.addEventListener('click', extractContent);
  186. buttonContainer.appendChild(extractButton);
  187.  
  188. const nextChapterButton = document.createElement('button');
  189. nextChapterButton.textContent = 'Chuyển đến chương tiếp theo';
  190. nextChapterButton.style.padding = '8px 15px';
  191. nextChapterButton.style.backgroundColor = '#2196f3';
  192. nextChapterButton.style.color = 'white';
  193. nextChapterButton.style.border = 'none';
  194. nextChapterButton.style.borderRadius = '4px';
  195. nextChapterButton.style.cursor = 'pointer';
  196. nextChapterButton.style.display = 'none'; // Ẩn nút
  197. nextChapterButton.addEventListener('click', goToNextChapter);
  198. buttonContainer.appendChild(nextChapterButton);
  199.  
  200. const clearButton = document.createElement('button');
  201. clearButton.textContent = 'Xóa nội dung';
  202. clearButton.style.padding = '8px 15px';
  203. clearButton.style.backgroundColor = '#f44336';
  204. clearButton.style.color = 'white';
  205. clearButton.style.border = 'none';
  206. clearButton.style.borderRadius = '4px';
  207. clearButton.style.cursor = 'pointer';
  208. clearButton.addEventListener('click', clearContent);
  209. buttonContainer.appendChild(clearButton);
  210.  
  211. const copyButton = document.createElement('button');
  212. copyButton.textContent = 'Sao chép nội dung';
  213. copyButton.style.padding = '8px 15px';
  214. copyButton.style.backgroundColor = '#ff9800';
  215. copyButton.style.color = 'white';
  216. copyButton.style.border = 'none';
  217. copyButton.style.borderRadius = '4px';
  218. copyButton.style.cursor = 'pointer';
  219. copyButton.addEventListener('click', copyContent);
  220. buttonContainer.appendChild(copyButton);
  221.  
  222. container.appendChild(buttonContainer);
  223. document.body.appendChild(container);
  224. }
  225.  
  226. // Extract content from current page
  227. function extractContent() {
  228. const textarea = document.getElementById('extracted-content');
  229. // Get chapter title
  230. const chapterTitle = document.querySelector('h2');
  231. let titleText = chapterTitle ? chapterTitle.textContent.trim() : 'Không tìm thấy tiêu đề';
  232. // Get chapter content
  233. const chapterContentBox = document.querySelector('.box-chap');
  234. let contentText = '';
  235. if (chapterContentBox) {
  236. // Remove unwanted elements like scripts, styles, ads
  237. const contentClone = chapterContentBox.cloneNode(true);
  238. const scripts = contentClone.querySelectorAll('script, style, .ads, .banner, .comment');
  239. scripts.forEach(script => script.remove());
  240. // Get the clean text
  241. contentText = contentClone.innerText.trim();
  242. } else {
  243. contentText = 'Không tìm thấy nội dung chương';
  244. }
  245. // Append to existing content
  246. textarea.value += `\n\n${titleText}\n\n${contentText}`;
  247. // Save content to localStorage
  248. localStorage.setItem('extractedNovelContent', textarea.value);
  249. // Scroll to bottom of textarea
  250. textarea.scrollTop = textarea.scrollHeight;
  251. }
  252.  
  253. // Go to next chapter
  254. function goToNextChapter() {
  255. const nextButton = document.querySelector('.bot-next_chap.bot-control');
  256. if (nextButton) {
  257. // Extract current content before moving to next chapter
  258. extractContent();
  259. // Navigate to next chapter
  260. nextButton.click();
  261. // Add a delay to let the next page load before extracting content
  262. setTimeout(() => {
  263. // Don't clear the textarea, just append the new content
  264. extractContent();
  265. // Show notification
  266. const notification = document.createElement('div');
  267. notification.textContent = 'Đã thêm nội dung chương mới';
  268. notification.style.position = 'fixed';
  269. notification.style.bottom = '20px';
  270. notification.style.right = '320px';
  271. notification.style.backgroundColor = '#4caf50';
  272. notification.style.color = 'white';
  273. notification.style.padding = '10px';
  274. notification.style.borderRadius = '5px';
  275. notification.style.zIndex = '10000';
  276. document.body.appendChild(notification);
  277. // Remove notification after 3 seconds
  278. setTimeout(() => {
  279. document.body.removeChild(notification);
  280. }, 3000);
  281. }, 2000);
  282. } else {
  283. alert('Không tìm thấy nút chuyển đến chương tiếp theo');
  284. }
  285. }
  286.  
  287. // Clear content in textarea
  288. function clearContent() {
  289. const textarea = document.getElementById('extracted-content');
  290. textarea.value = '';
  291. // Also clear the saved content
  292. localStorage.removeItem('extractedNovelContent');
  293. }
  294.  
  295. // Copy content to clipboard
  296. function copyContent() {
  297. const textarea = document.getElementById('extracted-content');
  298. textarea.select();
  299. document.execCommand('copy');
  300. // Visual feedback
  301. const originalColor = textarea.style.backgroundColor;
  302. textarea.style.backgroundColor = '#e6ffe6';
  303. setTimeout(() => {
  304. textarea.style.backgroundColor = originalColor;
  305. }, 500);
  306. }
  307.  
  308. // Initialize when page is loaded
  309. function init() {
  310. createContainer();
  311. // Không tự động trích xuất khi tải trang nữa
  312. // Người dùng sẽ cần nhấn nút "Bắt đầu lấy text"
  313. }
  314.  
  315. // Run when page is fully loaded
  316. window.addEventListener('load', init);
  317. })();