Copy-Text

Merge and copy

  1. // ==UserScript==
  2. // @name Copy-Text
  3. // @version 1.0
  4. // @description Merge and copy
  5. // @author Ep Tien Sinh
  6. // @match *://69shuba.cx/*/*
  7. // @match *://www.qidian.com/chapter/*
  8. // @match *://fanqienovel.com/reader/*
  9. // @match *://www.ixdzs8.tw/*
  10. // @match *://www.qimao.com/*/*
  11. // @match *://www.keleshuba.net/*
  12. // @match *://www.17k.com/*
  13. // @match *://www.piaotia.com/*/*/*/*
  14. // @grant GM_setClipboard
  15. // @grant GM_download
  16. // @namespace https://greasyfork.org/users/1402485
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. // Cấu hình cho từng trang bằng cách sử dụng một đối tượng
  23. var pageConfigs = [
  24. {
  25. urlContains: '69shuba.cx/*',
  26. headerSelector: 'body > div.container > div.mybox > div.txtnav > h1',
  27. contentSelector: 'body > div.container > div.mybox > div.txtnav',
  28. trashSelectors: [
  29. '#txtright',
  30. 'div.contentadv',
  31. 'div.bottom-ad',
  32. 'div.txtinfo.hide720'
  33. // Thêm các selector 'rác' khác tại đây
  34. ]
  35. },
  36. {
  37. urlContains: 'www.qidian.com',
  38. headerSelector: '#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > h1',
  39. contentSelector: 'div.enable-review',
  40. trashSelectors: [
  41. '#reader-content > div > div > div.relative > div > div.text-s-gray-500.mt-4px.text-bo4.flex.items-center.flex-wrap',
  42. 'span.review'
  43. ]
  44. },
  45. {
  46. urlContains: 'fanqienovel.com',
  47. headerSelector: 'div.muye-reader-box-header > h1',
  48. contentSelector: 'div.muye-reader-content'
  49. },
  50. {
  51. urlContains: 'ixdzs8.tw',
  52. headerSelector: '#page > article > h3',
  53. contentSelector: '#page > article > section'
  54. },
  55. {
  56. urlContains: 'www.qimao.com',
  57. headerSelector: '#__layout > div > div.wrapper.reader.reader-layout-theme > div.main > div > div > div > div.chapter-detail-wrap.reader-box > div.chapter-detail-wrap-info > h2',
  58. contentSelector: '#__layout > div > div.wrapper.reader.reader-layout-theme > div.main > div > div > div > div.chapter-detail-wrap.reader-box > div.chapter-detail-wrap-content > div.show-part > div'
  59. },
  60. {
  61. urlContains: 'www.keleshuba.net',
  62. headerSelector: '#nr_title',
  63. contentSelector: '#nr1',
  64. trashSelectors1: [
  65. 'div[data-ad-slot="1016693305"]'
  66. ]
  67. },
  68. {
  69. urlContains: 'www.17k.com',
  70. headerSelector: '#nr_title',
  71. contentSelector: '#nr1',
  72. trashSelectors1: [
  73. 'div[data-ad-slot="1016693305"]'
  74. ]
  75. },
  76. {
  77. urlContains: 'www.piaotia.com',
  78. headerSelector: '#content > h1',
  79. contentSelector: '#content',
  80. trashSelectors1: [
  81. '#content > div',
  82. '#content > table'
  83. ]
  84. },
  85.  
  86. // Thêm cấu hình cho các trang khác tương tự
  87. ];
  88.  
  89. function mergeAndCopy(config) {
  90. var headerElement = document.querySelector(config.headerSelector);
  91. var contentElement = document.querySelector(config.contentSelector);
  92.  
  93. var trashSelectors = config.trashSelectors || [];
  94. trashSelectors.forEach(function(selector) {
  95. var trashElements = document.querySelectorAll(selector);
  96. trashElements.forEach(function(element) {
  97. element.remove();
  98. });
  99. });
  100.  
  101. if (headerElement && contentElement) {
  102. var headerContent = headerElement.textContent.trim().replace(/\s{2,}/g, '\n');
  103. var contentHtml = contentElement.innerHTML;
  104.  
  105. var contentText = contentHtml.replace(/ /g, ' ')
  106. .replace('(adsbygoogle = window.adsbygoogle || []).push({});', '')
  107. .replace(/<br\s*[\/]?>/gi, '\n')
  108. .replace(/<\/p>/gi, '\n')
  109. .replace(/<p[^>]*>/gi, '')
  110. .replace(/<[^>]+>/g, '');
  111.  
  112. contentText = contentText.trim().replace(/\s{2,}/g, '\n').replace(/\n{3,}/g, '\n\n');
  113.  
  114. var lines = contentText.split('\n');
  115. var headerPattern = headerContent.replace(/第\d+章/, '第\\d+章');
  116. var headerRegex = new RegExp(headerPattern);
  117.  
  118. if (lines.length > 0 && headerRegex.test(lines[0].trim())) {
  119. lines[0] = lines[0].replace(headerRegex, '').trim();
  120. }
  121. contentText = lines.join('\n').trim();
  122.  
  123. if (window.location.href.includes('www.qimao.com')) {
  124. var headerLines = headerContent.split('\n');
  125. if (headerLines.length > 1) {
  126. headerContent = headerLines.join(' ').trim(); // Gộp hai dòng tiêu đề lại
  127. }
  128. }
  129.  
  130. var mergedContent = headerContent + '\n\n' + contentText + '\n\n';
  131. var mergedLines = mergedContent.split('\n');
  132. if (window.location.href.includes('www.piaotia.com')) {
  133. if (mergedLines.length > 10) {
  134. mergedContent = mergedLines.slice(10).join('\n');
  135. }
  136. }
  137. else if (window.location.href.includes('69shuba.cx')) {
  138. var wrongChapter = /^\d+\.\s*(第\d+章)/;
  139. var correctChapter = /^第\d+章/;
  140.  
  141. var line = mergedLines[0].trim();
  142.  
  143. if (wrongChapter.test(line)) {
  144. mergedLines[0] = line.replace(wrongChapter, '$1').trim();
  145. }
  146. if (mergedLines.length > 2) {
  147. var line3 = mergedLines[2].trim();
  148. if (correctChapter.test(line3)) {
  149. mergedLines.splice(2, 1);
  150. }
  151. }
  152.  
  153. mergedContent = mergedLines.join('\n');
  154. }
  155.  
  156. return mergedContent;
  157. }
  158. return '';
  159. }
  160.  
  161. function navigate(direction) {
  162. var buttonTexts = direction === 'next' ? ['下一章', '下一页'] : ['上一章', '上一页'];
  163. var button = null;
  164.  
  165. buttonTexts.some(text => {
  166. button = Array.from(document.querySelectorAll('a, button, span')).find(el => el.textContent.trim() === text);
  167. return button !== undefined; // Dừng vòng lặp nếu tìm thấy
  168. });
  169.  
  170. if (button) {
  171. if (button.tagName.toLowerCase() === 'a') {
  172. window.location.href = button.href;
  173. } else {
  174. button.click();
  175. }
  176. }
  177. }
  178.  
  179. function applyPageConfig() {
  180. var currentUrl = window.location.href;
  181. var config = pageConfigs.find(function(config) {
  182. return currentUrl.includes(config.urlContains);
  183. });
  184.  
  185. if (config) {
  186. return mergeAndCopy(config);
  187. }
  188. return '';
  189. }
  190.  
  191. function getCurrentPageConfig() {
  192. var currentUrl = window.location.href;
  193. return pageConfigs.find(function(config) {
  194. return currentUrl.includes(config.urlContains);
  195. });
  196. }
  197.  
  198. function checkNavigationButtons() {
  199. var nextTexts = ['下一章', '下一页'];
  200. var prevTexts = ['上一章', '上一页'];
  201.  
  202. var nextButton = null;
  203. var backButton = null;
  204.  
  205. nextTexts.some(text => {
  206. nextButton = Array.from(document.querySelectorAll('a, button, span')).find(el => el.textContent.trim() === text);
  207. return nextButton !== undefined;
  208. });
  209.  
  210. prevTexts.some(text => {
  211. backButton = Array.from(document.querySelectorAll('a, button, span')).find(el => el.textContent.trim() === text);
  212. return backButton !== undefined;
  213. });
  214.  
  215. if (nextButton) {
  216. nextButton.style.display = 'block';
  217. }
  218.  
  219. if (backButton) {
  220. backButton.style.display = 'block';
  221. }
  222. }
  223.  
  224. function checkNavigationButtonsOnLoad() {
  225. checkNavigationButtons();
  226. }
  227.  
  228. var autoClickInterval;
  229. var isCopying = false;
  230. var copiedChapters = [];
  231.  
  232. function startAutoClick() {
  233. autoClickInterval = setInterval(function() {
  234.  
  235. if (!isCopying) {
  236. isCopying = true;
  237.  
  238. var currentPageConfig = getCurrentPageConfig();
  239. if (currentPageConfig) {
  240. var mergedContent = applyPageConfig();
  241.  
  242. if (!copiedChapters.includes(mergedContent)) {
  243. appendToClipboard(mergedContent);
  244. copiedChapters.push(mergedContent);
  245. }
  246. }
  247.  
  248. setTimeout(function() {
  249. var nextButtonExists = checkNextButtonExists();
  250.  
  251. if (!nextButtonExists) {
  252. // Dừng auto-click nếu không còn chương tiếp theo
  253. stopAutoClick();
  254. return;
  255. }
  256. navigate('next');
  257. setTimeout(function() {
  258. isCopying = false;
  259. }, 1000); // Tăng thêm thời gian chờ sau khi chuyển chương để đảm bảo quá trình copy hoàn thành
  260. }, 800); // Chuyển chương sau 0.8 giây
  261. }
  262. }, 1500); // Điều chỉnh thời gian chờ để tránh copy lặp lại (tăng lên 1.5 giây)
  263.  
  264. autoClickButton.textContent = 'Stop Auto';
  265. localStorage.setItem('autoClickRunning', 'true');
  266. }
  267.  
  268. function checkNextButtonExists() {
  269. var buttonTexts = ['下一章', '下一页']; // Các văn bản cho nút "Next"
  270. var nextButton = null;
  271.  
  272. buttonTexts.some(text => {
  273. nextButton = Array.from(document.querySelectorAll('a, button, span')).find(el => el.textContent.trim() === text);
  274. return nextButton !== undefined;
  275. });
  276. return nextButton !== undefined;
  277. }
  278.  
  279. function clearClipboardAndStartAutoClick() {
  280. navigator.clipboard.writeText('').then(function() {
  281. startAutoClick();
  282. }, function(err) {
  283. });
  284. }
  285.  
  286. function appendToClipboard(newContent) {
  287. navigator.clipboard.readText().then(function(currentContent) {
  288. const combinedContent = currentContent + newContent;
  289. navigator.clipboard.writeText(combinedContent).then(function() {
  290. }, function(err) {
  291. });
  292. }, function(err) {
  293. });
  294. }
  295.  
  296. function stopAutoClick() {
  297. clearInterval(autoClickInterval);
  298. autoClickInterval = null;
  299. autoClickButton.textContent = 'Auto Click';
  300.  
  301. localStorage.removeItem('autoClickRunning');
  302.  
  303. var headerText = 'clipboard';
  304. navigator.clipboard.readText().then(clipboardContent => {
  305.  
  306. if (clipboardContent) {
  307. var blob = new Blob([clipboardContent], { type: 'text/plain' });
  308. let downloadLink = window.URL.createObjectURL(blob);
  309. let downloadArgs = {
  310. url: downloadLink,
  311. name: `${headerText}.txt`
  312. };
  313. GM_download(downloadArgs);
  314. }
  315. }).catch(err => {
  316. });
  317. }
  318.  
  319. var copyNextButton = createButton('Copy & Next', '50px', '490px', function() {
  320. var mergedContent = applyPageConfig(); // Lấy nội dung hợp nhất
  321. GM_setClipboard(mergedContent);
  322. setTimeout(function() {
  323. navigate('next');
  324. }, 1000);
  325. });
  326. document.body.appendChild(copyNextButton);
  327.  
  328. var autoClickButton = createButton('Auto Click', '50px', '370px', function() {
  329. if (!autoClickInterval) {
  330. clearClipboardAndStartAutoClick();
  331. } else {
  332. stopAutoClick();
  333. }
  334. });
  335. document.body.appendChild(autoClickButton);
  336.  
  337. var nextButton = createButton('Next Chương', '10px', '490px', function() {
  338. navigate('next');
  339. checkNavigationButtons();
  340. });
  341. document.body.appendChild(nextButton);
  342.  
  343. var backButton = createButton('Back Chương', '10px', '370px', function() {
  344. navigate('back');
  345. checkNavigationButtons();
  346. });
  347. document.body.appendChild(backButton);
  348.  
  349. function createButton(text, bottom, left, clickHandler) {
  350. var button = document.createElement('button');
  351. button.textContent = text;
  352. button.style.position = 'fixed';
  353. button.style.bottom = bottom;
  354. button.style.left = left;
  355. button.style.zIndex = '9999';
  356. button.style.width = '110px';
  357. button.style.height = '35px';
  358. button.style.backgroundColor = text.includes('Next') ? 'green' : 'blue';
  359. button.style.color = 'white';
  360.  
  361. button.addEventListener('mousedown', function() {
  362. button.style.backgroundColor = 'yellow';
  363. button.style.color = 'black';
  364. });
  365.  
  366. button.addEventListener('mouseup', function() {
  367. button.style.backgroundColor = text.includes('Next') ? 'green' : 'blue';
  368. button.style.color = 'white';
  369. });
  370.  
  371. button.addEventListener('click', clickHandler);
  372.  
  373. return button;
  374. }
  375.  
  376. if (localStorage.getItem('autoClickRunning') === 'true') {
  377. startAutoClick();
  378. }
  379.  
  380. function main() {
  381. checkNavigationButtonsOnLoad();
  382. applyPageConfig();
  383. }
  384. document.addEventListener('DOMContentLoaded', main);
  385. })();