210vn-dl

Script dùng để download manga R18 trên 1 domain của hentaivn

  1. // ==UserScript==
  2. // @name 210vn-dl
  3. // @namespace https://gist.github.com/hiroshil
  4. // @version 0.0.6
  5. // @description Script dùng để download manga R18 trên 1 domain của hentaivn
  6. // @license MIT
  7. // @author hiroshil
  8. // @source https://gist.github.com/hiroshil/b85af14867493a72bd1cb24831bf0668
  9. // @include http*://*.*/*doc-truyen*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=hentaivn.icu
  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/3754092/how-to-get-a-html-element-from-a-string-with-jquery
  16. //https://stackoverflow.com/questions/30008114/how-do-i-promisify-native-xhr
  17. //https://stackoverflow.com/questions/5582574/how-to-check-if-a-string-contains-text-from-an-array-of-substrings-in-javascript
  18.  
  19. function waitForElm(selector) {
  20. return new Promise(resolve => {
  21. if ($(selector).length) {
  22. return resolve($(selector));
  23. }
  24. const observer = new MutationObserver(mutations => {
  25. if ($(selector).length) {
  26. resolve($(selector));
  27. observer.disconnect();
  28. }
  29. });
  30. observer.observe(document.body, {
  31. childList: true,
  32. subtree: true
  33. });
  34. });
  35. }
  36. function waitForXHRRequest(url,method,responseType) {
  37. return new Promise( (resolve, reject) => {
  38. var res = new XMLHttpRequest();
  39. res.responseType = responseType;
  40. res.open(method, url, true);
  41. res.send();
  42. res.onload = () => {
  43. if (res.status >= 200 && res.status < 400) {
  44. resolve(res.response);
  45. } else {
  46. reject(false);
  47. }
  48. }
  49. });
  50.  
  51. }
  52. function sleeper(ms) {
  53. return function(x) {
  54. return new Promise(resolve => setTimeout(() => resolve(x), ms));
  55. };
  56. }
  57. function downloadChapter(id,filename, callback, ret = 3, skipCr = true){
  58. $.post("../ajax_load_server.php", {
  59. server_id: id,
  60. server_type: 2
  61. },async (res) => {
  62. if (res){
  63. const imgs = $(res).filter("img");
  64. const zipFileWriter = new zip.BlobWriter();
  65. const zipWriter = new zip.ZipWriter(zipFileWriter);
  66. for (let i = 0; i < imgs.length; i++) {
  67. const src = imgs[i].src;
  68. if (skipCr) {
  69. if ( src.split("?")[0].endsWith(".gif") ) continue;
  70. }
  71. var blob;
  72. do {
  73. blob = await waitForXHRRequest(src,'GET','blob');
  74. ret -= 1;
  75. if (!blob && !ret) {
  76. alert("Lỗi khi download file: " + src)
  77. }
  78. else
  79. {
  80. await sleeper(200);
  81. }
  82. }
  83. while (!blob && ret);
  84. if (blob.type.includes("image")){
  85. const blobReader = new zip.BlobReader(blob);
  86. await zipWriter.add(String(i) + "_" + src.split("?").shift().split("/").pop(), blobReader);
  87. }
  88. }
  89. await zipWriter.close();
  90. const zipFileBlob = await zipFileWriter.getData();
  91. const anchor = document.createElement("a");
  92. const clickEvent = new MouseEvent("click");
  93. anchor.href = window.URL.createObjectURL(zipFileBlob);
  94. anchor.download = filename;
  95. anchor.dispatchEvent(clickEvent);
  96. }
  97. else {
  98. alert("Download không thành công!! Vui lòng thử lại!");
  99. }
  100. callback();
  101. });
  102. }
  103. function setupButton(jNode) {
  104. jNode.each(function() {
  105. const td = $("<td></td>");
  106. const button = $("<button></button>").addClass("dl-btn");
  107. button.text("Download");
  108. button.bind('click',function() {
  109. const chapURL = $(this).parent().parent()[0].firstElementChild.firstElementChild;
  110. $(this).attr('disabled','disabled');
  111. let hname = $("h1[itemprop='name']")[0].innerText;
  112. const cfilter = ["chap", "oneshot", "one shot"];
  113. if ( cfilter.find(s => hname.toLowerCase().includes(s)) ) hname = hname.split("-")[0].trim();
  114. const output = hname + " - " + chapURL.innerText + ".zip";
  115. downloadChapter(chapURL.href.split("-").at(1), output, () => { $(".dl-btn[disabled]").removeAttr('disabled'); });
  116. });
  117. td.append(button);
  118. $(this).append(td);
  119. });
  120. }
  121. async function main(){
  122. var xhr = await waitForXHRRequest("https://raw.githubusercontent.com/gildas-lormeau/zip.js/v2.7.17/dist/zip.js","GET",undefined);
  123. eval(xhr);
  124. const jNode = await waitForElm('#inner-listshowchapter > table > tbody > tr');
  125. setupButton(jNode);
  126. }
  127. const regex = /^https:\/\/[^/]+\.[^/]+\/\d+-doc-truyen-[^/]+\.html$/;
  128. if (regex.test(window.location.href)) main();