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 4.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 isAutoDownloading = false;
  16. let isLoaded = false;
  17.  
  18. // Giao diện
  19. const panel = document.createElement('div');
  20. panel.innerHTML = `
  21. <div style="position: fixed; top: 10%; right: 10px; width: 300px; z-index: 9999; background: #fff; border: 1px solid #ccc; padding: 10px; font-family: sans-serif;">
  22. <textarea id="content-textarea" style="width: 100%; height: 200px; margin-bottom: 10px;"></textarea>
  23. <button id="start-btn">Bt đầu</button>
  24. <button id="clear-btn">Xoá</button>
  25. <button id="copy-btn">Sao chép</button>
  26. <div style="margin-top:5px; font-size: 12px; color: gray;">T động t chương hin ti đến hết.</div>
  27. </div>`;
  28. document.body.appendChild(panel);
  29.  
  30. const textarea = document.getElementById('content-textarea');
  31. const startBtn = document.getElementById('start-btn');
  32. const clearBtn = document.getElementById('clear-btn');
  33. const copyBtn = document.getElementById('copy-btn');
  34.  
  35. // Lưu và khôi phục nội dung
  36. textarea.value = localStorage.getItem('chapterDownloaderContent') || '';
  37. textarea.addEventListener('input', () => {
  38. localStorage.setItem('chapterDownloaderContent', textarea.value);
  39. });
  40.  
  41. clearBtn.onclick = () => {
  42. textarea.value = '';
  43. localStorage.removeItem('chapterDownloaderContent');
  44. };
  45.  
  46. copyBtn.onclick = () => {
  47. textarea.select();
  48. document.execCommand('copy');
  49. alert('Đã sao chép!');
  50. };
  51.  
  52. function extractChapterContent() {
  53. const title = document.querySelector('h2')?.innerText.trim();
  54. const content = document.querySelector('.box-chap')?.innerText.trim();
  55. if (!title || !content) return false;
  56.  
  57. textarea.value += `\n\n---\n\n${title}\n\n${content}`;
  58. localStorage.setItem('chapterDownloaderContent', textarea.value);
  59. return true;
  60. }
  61.  
  62. async function fetchChapterList() {
  63. const storySlug = window.location.pathname.split('/')[2];
  64. const listUrl = `https://truyen.tangthuvien.vn/danh-sach-chuong/${storySlug}`;
  65.  
  66. const html = await fetch(listUrl).then(res => res.text());
  67. const temp = document.createElement('div');
  68. temp.innerHTML = html;
  69.  
  70. const links = Array.from(temp.querySelectorAll('a[href*="/doc-truyen/"]'));
  71. const urls = links.map(a => a.href.split('?')[0]);
  72. return [...new Set(urls)];
  73. }
  74.  
  75. async function startAutoDownload() {
  76. isAutoDownloading = true;
  77. startBtn.textContent = 'Đang chạy...';
  78.  
  79. if (!isLoaded) {
  80. chapterUrls = await fetchChapterList();
  81. isLoaded = true;
  82. }
  83.  
  84. const currentUrl = window.location.href.split('?')[0];
  85. let startIndex = chapterUrls.findIndex(url => url === currentUrl);
  86.  
  87. if (startIndex === -1) {
  88. alert('Không tìm thấy chương hiện tại trong danh sách!');
  89. isAutoDownloading = false;
  90. return;
  91. }
  92.  
  93. for (let i = startIndex; i < chapterUrls.length; i++) {
  94. const url = chapterUrls[i];
  95. console.log(`Ti chương ${i + 1}: ${url}`);
  96. await fetch(url)
  97. .then(res => res.text())
  98. .then(html => {
  99. const temp = document.createElement('div');
  100. temp.innerHTML = html;
  101.  
  102. const title = temp.querySelector('h2')?.innerText.trim();
  103. const content = temp.querySelector('.box-chap')?.innerText.trim();
  104.  
  105. if (title && content) {
  106. textarea.value += `\n\n---\n\n${title}\n\n${content}`;
  107. localStorage.setItem('chapterDownloaderContent', textarea.value);
  108. } else {
  109. console.warn('Không lấy được nội dung chương:', url);
  110. }
  111. });
  112.  
  113. await new Promise(resolve => setTimeout(resolve, 1000)); // nghỉ 1s
  114. }
  115.  
  116. alert('Đã tải xong toàn bộ chương!');
  117. startBtn.textContent = 'Bắt đầu';
  118. isAutoDownloading = false;
  119. }
  120.  
  121. startBtn.onclick = () => {
  122. if (!isAutoDownloading) {
  123. startAutoDownload();
  124. }
  125. };
  126. })();