Tienes que iniciar sesión o registrarte para poder continuar.

n210-dl

Script used to download manga R18 on a domain of nhentai

Versão de: 13/04/2024. Veja: a última versão.

  1. // ==UserScript==
  2. // @name n210-dl
  3. // @namespace https://gist.github.com/hiroshil
  4. // @version 0.0.1
  5. // @description Script used to download manga R18 on a domain of nhentai
  6. // @license MIT
  7. // @author hiroshil
  8. // @source https://gist.github.com/hiroshil/86723bc557efa88931cf6b135e42a2b2
  9. // @match http*://nhentai.to/g/*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=nhentai.to
  11. // ==/UserScript==
  12. /* jshint esversion: 8 */
  13.  
  14. //https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists
  15. //https://stackoverflow.com/questions/30008114/how-do-i-promisify-native-xhr
  16. //https://stackoverflow.com/questions/5582574/how-to-check-if-a-string-contains-text-from-an-array-of-substrings-in-javascript
  17.  
  18. function waitForElm(selector) {
  19. return new Promise(resolve => {
  20. if (document.querySelectorAll(selector).length) {
  21. return resolve(document.querySelectorAll(selector));
  22. }
  23. const observer = new MutationObserver(mutations => {
  24. if (document.querySelectorAll(selector).length) {
  25. resolve(document.querySelectorAll(selector));
  26. observer.disconnect();
  27. }
  28. });
  29. observer.observe(document.body, {
  30. childList: true,
  31. subtree: true
  32. });
  33. });
  34. }
  35. function waitForXHRRequest(url,method,responseType) {
  36. return new Promise( (resolve, reject) => {
  37. var res = new XMLHttpRequest();
  38. res.responseType = responseType;
  39. res.open(method, url, true);
  40. res.send();
  41. res.onload = () => {
  42. if (res.status >= 200 && res.status < 400) {
  43. resolve(res.response);
  44. } else {
  45. reject(false);
  46. }
  47. }
  48. });
  49.  
  50. }
  51. function sleeper(ms) {
  52. return function(x) {
  53. return new Promise(resolve => setTimeout(() => resolve(x), ms));
  54. };
  55. }
  56. function parseStr(text) {
  57. /*
  58. Checks if the string matches the format "number-number" with the second number larger.
  59.  
  60. Args:
  61. text: The string to check.
  62.  
  63. Returns:
  64. Two numbers if the string matches the format and the second number is larger, False otherwise.
  65. */
  66. const pattern = /^\d+-\d+$/; // Matches "number-number" format
  67. const match = pattern.exec(text);
  68.  
  69. if (match) {
  70. const [num1, num2] = match[0].split("-"); // Split into two numbers
  71. if (parseInt(num1) < parseInt(num2)){ // Check if second number is larger
  72. return [parseInt(num1), parseInt(num2)]
  73. }
  74. }
  75.  
  76. return false;
  77. }
  78. async function downloadChapter(id=null,filename=null, callback=(e)=>{}, ret = 3, skipCr = true){
  79. console.log(id);
  80. const dlBtn = document.querySelector("#dlzip");
  81. if (!(dlBtn.classList.contains("btn-disabled"))) {
  82. dlBtn.classList.add("btn-disabled");
  83. var s_p = 1;
  84. var e_p = gallery.num_pages;
  85. let pt = prompt("Please enter the number of pages you want to download (Pattern: first page-last page. Example: 15-30)", "Click Continue to download all");
  86. const pg = parseStr(pt)
  87. if (pg) {
  88. s_p = pg[0];
  89. e_p = pg[1];
  90. }
  91. if (pt != null) {
  92. const srcUrl = document.querySelector("#cover > a > img").src;
  93. const media_url_ = new URL(srcUrl).origin;
  94. const ext = srcUrl.split(".").at(-1);
  95. const zipFileWriter = new zip.BlobWriter();
  96. const zipWriter = new zip.ZipWriter(zipFileWriter);
  97. for (let i = s_p; i <= e_p; i++) {
  98. const fname = i.toString() + "." + ext;
  99. const src = media_url_ + "/galleries/" + id + "/"+ fname;
  100. console.log((i+1).toString() + "/" + e_p.toString() + ": downloading "+src); //debug
  101. var blob;
  102. do {
  103. blob = await waitForXHRRequest(src,'GET','blob');
  104. ret -= 1;
  105. if (!blob && !ret) {
  106. alert("Error while downloading file: " + src)
  107. }
  108. else
  109. {
  110. await sleeper(200);
  111. }
  112. }
  113. while (!blob && ret);
  114. if (blob.type.includes("image")){
  115. const blobReader = new zip.BlobReader(blob);
  116. await zipWriter.add(fname, blobReader);
  117. }
  118. }
  119. await zipWriter.close();
  120. const zipFileBlob = await zipFileWriter.getData();
  121. const anchor = document.createElement("a");
  122. const clickEvent = new MouseEvent("click");
  123. anchor.href = window.URL.createObjectURL(zipFileBlob);
  124. anchor.download = filename;
  125. anchor.dispatchEvent(clickEvent);
  126. }
  127. }
  128. callback(dlBtn);
  129. }
  130. function setupButton(jNode) {
  131. const btnDiv = document.querySelector(".buttons"); // Get the last child of the div with class "buttons"
  132. jNode.forEach(function(dlElement) {
  133. const clonedElement = dlElement.cloneNode(true); // Clone the element with all its content
  134. clonedElement.id = "dlzip";
  135. clonedElement.classList.remove("btn-disabled");
  136. clonedElement.querySelector(".top").textContent = "Click to download as zip";
  137.  
  138. btnDiv.appendChild(clonedElement); // Append the cloned element to the last child
  139.  
  140. clonedElement.addEventListener("click", (e)=>{
  141. downloadChapter(gallery.media_id, gallery.title.japanese + ".zip", (el)=>{ el.classList.remove("btn-disabled"); });
  142. });
  143. });
  144. }
  145. async function main(){
  146. var xhr = await waitForXHRRequest("https://raw.githubusercontent.com/gildas-lormeau/zip.js/v2.7.17/dist/zip.js","GET",undefined);
  147. eval(xhr);
  148. const btn = await waitForElm('#download');
  149. setupButton(btn);
  150. }
  151. main();