Chapter Downloader

Tự động trích xuất nội dung truyện từ truyen.tangthuvien.net

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

  1. // ==UserScript==
  2. // @name Chapter Downloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Tự động trích xuất nội dung truyện từ truyen.tangthuvien.net
  6. // @author TangThuVienExtractor
  7. // @match https://truyen.tangthuvien.net/doc-truyen/*/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Biến toàn cục để theo dõi trạng thái trích xuất tự động
  15. let isAutomaticExtraction = false;
  16.  
  17. // Tạo panel ở bên phải trang
  18. function createPanel() {
  19. // Tạo container chính cho panel
  20. const panel = document.createElement('div');
  21. panel.style.position = 'fixed';
  22. panel.style.top = '100px';
  23. panel.style.right = '20px';
  24. panel.style.width = '300px';
  25. panel.style.backgroundColor = '#f9f9f9';
  26. panel.style.border = '1px solid #ddd';
  27. panel.style.borderRadius = '5px';
  28. panel.style.padding = '10px';
  29. panel.style.zIndex = '9999';
  30. panel.style.display = 'flex';
  31. panel.style.flexDirection = 'column';
  32. panel.style.gap = '10px';
  33. panel.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)';
  34.  
  35. // Tạo tiêu đề panel
  36. const title = document.createElement('h3');
  37. title.textContent = 'Trích xuất nội dung truyện';
  38. title.style.margin = '0 0 10px 0';
  39. title.style.textAlign = 'center';
  40. title.style.borderBottom = '1px solid #ddd';
  41. title.style.paddingBottom = '10px';
  42. panel.appendChild(title);
  43.  
  44. // Tạo textarea để hiển thị nội dung đã trích xuất
  45. const textarea = document.createElement('textarea');
  46. textarea.style.width = '100%';
  47. textarea.style.height = '200px';
  48. textarea.style.padding = '8px';
  49. textarea.style.borderRadius = '3px';
  50. textarea.style.border = '1px solid #ddd';
  51. textarea.style.marginBottom = '10px';
  52. textarea.style.resize = 'vertical';
  53. panel.appendChild(textarea);
  54.  
  55. // Lấy nội dung đã lưu từ localStorage (nếu có)
  56. const savedContent = localStorage.getItem('tangthuvien_extracted_content');
  57. if (savedContent) {
  58. textarea.value = savedContent;
  59. }
  60.  
  61. // Tạo container cho các nút
  62. const buttonContainer = document.createElement('div');
  63. buttonContainer.style.display = 'flex';
  64. buttonContainer.style.flexDirection = 'column';
  65. buttonContainer.style.gap = '5px';
  66. panel.appendChild(buttonContainer);
  67.  
  68. // Tạo nút bắt đầu trích xuất
  69. const startButton = document.createElement('button');
  70. startButton.textContent = 'Bắt đầu lấy text';
  71. startButton.style.padding = '8px';
  72. startButton.style.backgroundColor = '#4caf50';
  73. startButton.style.color = 'white';
  74. startButton.style.border = 'none';
  75. startButton.style.borderRadius = '3px';
  76. startButton.style.cursor = 'pointer';
  77. startButton.addEventListener('click', function() {
  78. if (!isAutomaticExtraction) {
  79. isAutomaticExtraction = true;
  80. startButton.textContent = 'Đang trích xuất...';
  81. startButton.style.backgroundColor = '#ff9800';
  82. // Bắt đầu quá trình trích xuất tự động
  83. autoExtractAndNavigate();
  84. } else {
  85. isAutomaticExtraction = false;
  86. startButton.textContent = 'Bắt đầu lấy text';
  87. startButton.style.backgroundColor = '#4caf50';
  88. }
  89. });
  90. buttonContainer.appendChild(startButton);
  91.  
  92. // Tạo nút xóa nội dung
  93. const clearButton = document.createElement('button');
  94. clearButton.textContent = 'Xóa nội dung';
  95. clearButton.style.padding = '8px';
  96. clearButton.style.backgroundColor = '#f44336';
  97. clearButton.style.color = 'white';
  98. clearButton.style.border = 'none';
  99. clearButton.style.borderRadius = '3px';
  100. clearButton.style.cursor = 'pointer';
  101. clearButton.addEventListener('click', function() {
  102. textarea.value = '';
  103. localStorage.removeItem('tangthuvien_extracted_content');
  104. // Hiển thị thông báo
  105. const notification = document.createElement('div');
  106. notification.textContent = 'Đã xóa nội dung';
  107. notification.style.position = 'fixed';
  108. notification.style.bottom = '20px';
  109. notification.style.right = '20px';
  110. notification.style.backgroundColor = '#f44336';
  111. notification.style.color = 'white';
  112. notification.style.padding = '10px';
  113. notification.style.borderRadius = '5px';
  114. notification.style.zIndex = '10000';
  115. document.body.appendChild(notification);
  116. // Xóa thông báo sau 3 giây
  117. setTimeout(() => {
  118. document.body.removeChild(notification);
  119. }, 3000);
  120. });
  121. buttonContainer.appendChild(clearButton);
  122.  
  123. // Tạo nút sao chép nội dung
  124. const copyButton = document.createElement('button');
  125. copyButton.textContent = 'Sao chép nội dung';
  126. copyButton.style.padding = '8px';
  127. copyButton.style.backgroundColor = '#2196f3';
  128. copyButton.style.color = 'white';
  129. copyButton.style.border = 'none';
  130. copyButton.style.borderRadius = '3px';
  131. copyButton.style.cursor = 'pointer';
  132. copyButton.addEventListener('click', function() {
  133. textarea.select();
  134. document.execCommand('copy');
  135. // Hiển thị thông báo
  136. const notification = document.createElement('div');
  137. notification.textContent = 'Đã sao chép nội dung';
  138. notification.style.position = 'fixed';
  139. notification.style.bottom = '20px';
  140. notification.style.right = '20px';
  141. notification.style.backgroundColor = '#2196f3';
  142. notification.style.color = 'white';
  143. notification.style.padding = '10px';
  144. notification.style.borderRadius = '5px';
  145. notification.style.zIndex = '10000';
  146. document.body.appendChild(notification);
  147. // Xóa thông báo sau 3 giây
  148. setTimeout(() => {
  149. document.body.removeChild(notification);
  150. }, 3000);
  151. });
  152. buttonContainer.appendChild(copyButton);
  153.  
  154. // Thêm panel vào body
  155. document.body.appendChild(panel);
  156. // Trả về các phần tử để sử dụng sau này
  157. return {
  158. panel,
  159. textarea,
  160. startButton
  161. };
  162. }
  163.  
  164. // Hàm trích xuất nội dung chương hiện tại
  165. function extractCurrentChapterContent() {
  166. const panelElements = document.querySelector('textarea');
  167. const startButton = document.querySelector('button');
  168. if (!panelElements || !startButton) {
  169. console.error('Không tìm thấy panel hoặc textarea');
  170. return false;
  171. }
  172. // Lấy tiêu đề chương
  173. const chapterTitle = document.querySelector('h2');
  174. if (!chapterTitle) {
  175. console.error('Không tìm thấy tiêu đề chương');
  176. return false;
  177. }
  178. // Lấy nội dung chương
  179. const chapterContentSelector = '.box-chap';
  180. const chapterContent = document.querySelector(chapterContentSelector);
  181. if (!chapterContent) {
  182. console.error('Không tìm thấy nội dung chương');
  183. return false;
  184. }
  185. // Xử lý nội dung
  186. let contentText = chapterContent.innerText || chapterContent.textContent;
  187. contentText = contentText.trim();
  188. // Thêm nội dung vào textarea
  189. let currentContent = panelElements.value || '';
  190. // Thêm dấu phân cách nếu đã có nội dung trước đó
  191. if (currentContent !== '') {
  192. currentContent += '\n\n------------\n\n';
  193. }
  194. // Thêm tiêu đề và nội dung
  195. currentContent += chapterTitle.innerText + '\n\n' + contentText;
  196. // Cập nhật textarea và lưu vào localStorage
  197. panelElements.value = currentContent;
  198. localStorage.setItem('tangthuvien_extracted_content', currentContent);
  199. // Hiển thị thông báo
  200. const notification = document.createElement('div');
  201. notification.textContent = 'Đã trích xuất: ' + chapterTitle.innerText;
  202. notification.style.position = 'fixed';
  203. notification.style.bottom = '20px';
  204. notification.style.right = '320px';
  205. notification.style.backgroundColor = '#4caf50';
  206. notification.style.color = 'white';
  207. notification.style.padding = '10px';
  208. notification.style.borderRadius = '5px';
  209. notification.style.zIndex = '10000';
  210. document.body.appendChild(notification);
  211. // Xóa thông báo sau 3 giây
  212. setTimeout(() => {
  213. document.body.removeChild(notification);
  214. }, 3000);
  215. return true;
  216. }
  217.  
  218. // Hàm tự động trích xuất và chuyển trang
  219. function autoExtractAndNavigate() {
  220. if (!isAutomaticExtraction) {
  221. return;
  222. }
  223. // Trích xuất nội dung chương hiện tại
  224. const extractionSuccess = extractCurrentChapterContent();
  225. if (extractionSuccess) {
  226. // Tìm nút chuyển đến chương tiếp theo
  227. const nextButton = document.querySelector('.bot-next_chap.bot-control');
  228. // Kiểm tra xem có thông báo "Bạn đã đọc đến chương mới nhất" hay không
  229. const pageContent = document.body.innerText;
  230. if (pageContent.includes('Bạn đã đọc đến chương mới nhất')) {
  231. // Kết thúc quá trình khi thấy thông báo này
  232. isAutomaticExtraction = false;
  233. const startButton = document.querySelector('button');
  234. if (startButton) {
  235. startButton.textContent = 'Bắt đầu lấy text';
  236. startButton.style.backgroundColor = '#4caf50';
  237. }
  238. // Hiển thị thông báo hoàn thành
  239. const notification = document.createElement('div');
  240. notification.textContent = 'Đã hoàn thành trích xuất toàn bộ truyện!';
  241. notification.style.position = 'fixed';
  242. notification.style.bottom = '20px';
  243. notification.style.right = '320px';
  244. notification.style.backgroundColor = '#4caf50';
  245. notification.style.color = 'white';
  246. notification.style.padding = '10px';
  247. notification.style.borderRadius = '5px';
  248. notification.style.zIndex = '10000';
  249. document.body.appendChild(notification);
  250. // Xóa thông báo sau 5 giây
  251. setTimeout(() => {
  252. document.body.removeChild(notification);
  253. }, 5000);
  254. return;
  255. }
  256. if (nextButton) {
  257. // Hiển thị thông báo
  258. const notification = document.createElement('div');
  259. notification.textContent = 'Đang chuyển đến chương tiếp theo...';
  260. notification.style.position = 'fixed';
  261. notification.style.bottom = '20px';
  262. notification.style.right = '320px';
  263. notification.style.backgroundColor = '#ff9800';
  264. notification.style.color = 'white';
  265. notification.style.padding = '10px';
  266. notification.style.borderRadius = '5px';
  267. notification.style.zIndex = '10000';
  268. document.body.appendChild(notification);
  269. // Xóa thông báo sau 2 giây
  270. setTimeout(() => {
  271. document.body.removeChild(notification);
  272. }, 1000);
  273. // Nhấp vào nút chuyển trang
  274. nextButton.click();
  275. // Đợi 2 giây để trang mới tải xong, sau đó tiếp tục quá trình
  276. setTimeout(() => {
  277. // Kiểm tra xem nút có bị ẩn hay không
  278. const startButton = document.querySelector('button');
  279. // Nếu không tìm thấy nút hoặc nút không đúng trạng thái,
  280. // bắt đầu trực tiếp quá trình trích xuất
  281. // Hiển thị thông báo đang đợi trang tải
  282. const notification = document.createElement('div');
  283. notification.textContent = 'Đợi trang tải xong...';
  284. notification.style.position = 'fixed';
  285. notification.style.bottom = '20px';
  286. notification.style.right = '320px';
  287. notification.style.backgroundColor = '#FFA500';
  288. notification.style.color = 'white';
  289. notification.style.padding = '10px';
  290. notification.style.borderRadius = '5px';
  291. notification.style.zIndex = '10000';
  292. document.body.appendChild(notification);
  293. // Xóa thông báo và bắt đầu trích xuất sau 2 giây
  294. setTimeout(() => {
  295. document.body.removeChild(notification);
  296. autoExtractAndNavigate();
  297. }, 1000);
  298. }, 1000);
  299. } else {
  300. // Nếu không tìm thấy nút chuyển trang
  301. isAutomaticExtraction = false;
  302. const startButton = document.querySelector('button');
  303. if (startButton) {
  304. startButton.textContent = 'Bắt đầu lấy text';
  305. startButton.style.backgroundColor = '#4caf50';
  306. }
  307. // Hiển thị thông báo
  308. const notification = document.createElement('div');
  309. notification.textContent = 'Không tìm thấy nút chuyển trang';
  310. notification.style.position = 'fixed';
  311. notification.style.bottom = '20px';
  312. notification.style.right = '320px';
  313. notification.style.backgroundColor = '#f44336';
  314. notification.style.color = 'white';
  315. notification.style.padding = '10px';
  316. notification.style.borderRadius = '5px';
  317. notification.style.zIndex = '10000';
  318. document.body.appendChild(notification);
  319. // Xóa thông báo sau 5 giây
  320. setTimeout(() => {
  321. document.body.removeChild(notification);
  322. }, 5000);
  323. }
  324. } else {
  325. // Nếu trích xuất thất bại
  326. isAutomaticExtraction = false;
  327. const startButton = document.querySelector('button');
  328. if (startButton) {
  329. startButton.textContent = 'Bắt đầu lấy text';
  330. startButton.style.backgroundColor = '#4caf50';
  331. }
  332. // Hiển thị thông báo
  333. const notification = document.createElement('div');
  334. notification.textContent = 'Trích xuất thất bại';
  335. notification.style.position = 'fixed';
  336. notification.style.bottom = '20px';
  337. notification.style.right = '320px';
  338. notification.style.backgroundColor = '#f44336';
  339. notification.style.color = 'white';
  340. notification.style.padding = '10px';
  341. notification.style.borderRadius = '5px';
  342. notification.style.zIndex = '10000';
  343. document.body.appendChild(notification);
  344. // Xóa thông báo sau 5 giây
  345. setTimeout(() => {
  346. document.body.removeChild(notification);
  347. }, 5000);
  348. }
  349. }
  350.  
  351. // Khởi tạo panel khi trang đã tải xong
  352. window.addEventListener('load', function() {
  353. // Đợi 1 giây để đảm bảo trang đã tải hoàn toàn
  354. setTimeout(() => {
  355. createPanel();
  356. }, 1000);
  357. });
  358. })();