NewtokiRipper

Download Images From Newtoki

  1. // ==UserScript==
  2. // @name NewtokiRipper
  3. // @namespace adrian
  4. // @author adrian
  5. // @match https://newtoki468.com/webtoon/*
  6. // @version 1.3
  7. // @description Download Images From Newtoki
  8. // @require https://cdn.jsdelivr.net/npm/@violentmonkey/shortcut@1
  9. // @require https://unpkg.com/@zip.js/zip.js@2.7.60/dist/zip-full.min.js
  10. // @grant GM_registerMenuCommand
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. const fetchImage = async (url, name) => {
  15. const blob = await fetch(url, {
  16. headers: {
  17. accept:
  18. "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
  19. "accept-language": "en-US,en;q=0.9",
  20. "sec-ch-ua": '"Chromium";v="135", "Not-A.Brand";v="8"',
  21. "sec-ch-ua-mobile": "?0",
  22. "sec-ch-ua-platform": '"macOS"',
  23. "sec-fetch-dest": "image",
  24. "sec-fetch-mode": "no-cors",
  25. "sec-fetch-site": "cross-site",
  26. "sec-fetch-storage-access": "active",
  27. },
  28. referrer: "https://newtoki468.com/",
  29. referrerPolicy: "strict-origin-when-cross-origin",
  30. body: null,
  31. method: "GET",
  32. mode: "cors",
  33. credentials: "omit",
  34. }).then((response) => response.blob());
  35. return blob;
  36. };
  37.  
  38. const downloadImages = async () => {
  39. const images = [...document.getElementsByTagName("img")].flatMap((img) => {
  40. const attributes = [...img.attributes].filter((attr) =>
  41. /^data-[a-zA-Z0-9]{1,20}/.test(attr.name),
  42. );
  43. const actualSrc = attributes[0]?.value;
  44. if (actualSrc?.startsWith("https://img1.newtoki")) return [actualSrc];
  45. return [];
  46. });
  47. if (images.length === 0) return;
  48. const progressBar = document.createElement("div");
  49. progressBar.id = "dl-progress";
  50. progressBar.textContent = "Starting...";
  51. progressBar.style.padding = "20px";
  52. progressBar.style.backgroundColor = "black";
  53. progressBar.style.borderRadius = "10px";
  54. progressBar.style.border = "1px solid white";
  55. progressBar.style.boxShadow = "0 25px 50px -12px rgb(0 0 0 / 0.25)";
  56. progressBar.style.position = "fixed";
  57. progressBar.style.left = "50%";
  58. progressBar.style.top = "50%";
  59. progressBar.style.transform = "translate(-50%,-50%)";
  60. progressBar.style.zIndex = "9999";
  61. progressBar.style.fontSize = "20px";
  62. progressBar.style.color = "white";
  63. document.body.appendChild(progressBar);
  64. progressBar.textContent = `${images.length} images found.`;
  65. console.log(images);
  66. const zipWriter = new zip.ZipWriter(new zip.BlobWriter("application/zip"), {
  67. bufferedWrite: true,
  68. });
  69. console.log("starting zip generation");
  70. let progress = 1;
  71. await Promise.all(images.map(async (imageURL, i) => {
  72. const imageData = await fetchImage(imageURL, i);
  73. zipWriter.add(`${i+1}.jpg`, new zip.BlobReader(imageData), {});
  74. console.log(`fetched image ${i+1}/${images.length}`);
  75. progressBar.textContent = `fetched image ${progress}/${images.length}`;
  76. progress++;
  77. }));
  78. console.log("image fetching done. generating zip");
  79. progressBar.textContent = "image fetching done. generating zip";
  80. const blobURL = URL.createObjectURL(await zipWriter.close());
  81. const link = document.createElement("a");
  82. link.href = blobURL;
  83. link.download = `${document.title}.zip`;
  84. link.click();
  85. progressBar.textContent = "done.";
  86. setTimeout(() => progressBar.remove(), 1000);
  87. };
  88.  
  89. VM.shortcut.register("cm-s", downloadImages);
  90. VM.shortcut.enable();
  91.  
  92. GM_registerMenuCommand("Download Images (Ctrl/Cmd + S)", downloadImages);
  93.  
  94. const images = [...document.getElementsByTagName("img")].flatMap((img) => {
  95. const attributes = [...img.attributes].filter((attr) =>
  96. /^data-[a-zA-Z0-9]{1,20}/.test(attr.name),
  97. );
  98. const actualSrc = attributes[0]?.value;
  99. if (actualSrc?.startsWith("https://img1.newtoki")) return [actualSrc];
  100. return [];
  101. });
  102. if (images.length > 0) {
  103. const dlButton = document.createElement("button");
  104. dlButton.id = "dl-button";
  105. dlButton.textContent = "Download";
  106. dlButton.style.padding = "5px 12px";
  107. dlButton.style.backgroundColor = "#ef0029";
  108. dlButton.style.borderRadius = "8px";
  109. dlButton.style.border = "3px solid #000";
  110. dlButton.style.boxShadow = "0 4px 0 #000";
  111. dlButton.style.position = "fixed";
  112. dlButton.style.right = "130px";
  113. dlButton.style.bottom = "10px";
  114. dlButton.style.zIndex = "9999";
  115. dlButton.style.fontSize = "15px";
  116. dlButton.style.fontWeight = "800";
  117. dlButton.style.color = "white";
  118. dlButton.addEventListener("click", downloadImages);
  119. document.body.appendChild(dlButton);
  120. }