AsianSister.com Quick preview on homepage

Allows to Quick preview image collections on Homepage

  1. // ==UserScript==
  2. // @name:pl AsianSister.com Szybki podgląd na strone głównej
  3. // @name:en AsianSister.com Quick preview on homepage
  4. // @name AsianSister.com Quick preview on homepage
  5. // @namespace http://tampermonkey.net/
  6. // @version 1.2
  7. // @description:en Allows to Quick preview image collections on Homepage
  8. // @description:pl Umożliwia szybki podgląd kolecji obrazów na stronie głównej
  9. // @author TheUnsleepingAlchemist
  10. // @include /https?:\/\/asiansister.com\/(tag.|search.|_page[0-9]?).+/
  11. // @match https://asiansister.com/
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js
  13. // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js
  14. // @grant GM_addStyle
  15. // @grant GM_download
  16. // @run-at document-idle
  17. // @noframes
  18. // @description Allows to Quick preview image collections on Homepage
  19. // ==/UserScript==
  20.  
  21. /* FileSaver.min.js
  22. By Eli Grey
  23. License: MIT
  24. See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md */
  25.  
  26. /* jszip.min.js
  27. By Stuart Knightley, David Duponchel, Franz Buchinger, António Afonso
  28. License: GPL version 3
  29. See https://github.com/Stuk/jszip/blob/master/LICENSE.markdown */
  30.  
  31. (function() {
  32. 'use strict';
  33. //adding necessary CSS
  34. GM_addStyle(`.viewCountBox {pointer-events: none} .downloadInput {left: 10px;top: 2px;position: absolute;} .inputHidden {pointer-events: none;display:none} .inputShowen {pointer-events: all}`)
  35. //init varables
  36. let collections = [],
  37. collectionsList = [],
  38. collectionsToDownload = [],
  39. downloaded = 0,
  40. collIndex = 0,
  41. images = document.querySelectorAll(".imageBox img:not(.vip_cover)"),
  42. currentId = 0,
  43. hidden = false, //set on "true" if you wanna hide checkboxs
  44. imageQuality = "lq", //imageQuality represent quality of presented image possible options are "lq" and "hq", the last one is not recommended if you haven't good network connection
  45. selectBtn = document.createElement("div"),
  46. downloadBtn = document.createElement("div"),
  47. downloadAllBtn = document.createElement("div");
  48. //adding some HTML for fun
  49. selectBtn.innerHTML = `<svg style="width:24px;height:24px" viewBox="0 0 24 24">
  50. <path fill="currentColor" d="M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,5V19H5V5H19M10,17L6,13L7.41,11.58L10,14.17L16.59,7.58L18,9" />
  51. </svg><div class="headerMenuSpace"></div><div class="headerMenuSpace"></div>Select for Download`;
  52. selectBtn.style = `position: relative;top: 60px;align-items: center;display: flex;`;
  53. selectBtn.classList.add("leftMenu");
  54. downloadBtn.innerHTML = `<svg style="width:24px;height:24px" viewBox="0 0 24 24">
  55. <path fill="currentColor" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
  56. </svg><div class="headerMenuSpace"></div><div class="headerMenuSpace"></div>Download Selected`;
  57. downloadBtn.style = `position: relative;top: 60px;align-items: center;display: flex;`;
  58. downloadBtn.classList.add("leftMenu");
  59. downloadAllBtn.innerHTML = `<svg style="width:24px;height:24px" viewBox="0 0 24 24">
  60. <path fill="currentColor" d="M20,2H8A2,2 0 0,0 6,4V16A2,2 0 0,0 8,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M20,16H8V4H20V16M16,20V22H4A2,2 0 0,1 2,20V7H4V20H16M18.53,8.06L17.47,7L12.59,11.88L10.47,9.76L9.41,10.82L12.59,14L18.53,8.06Z" />
  61. </svg><div class="headerMenuSpace"></div><div class="headerMenuSpace"></div>Download All`;
  62. downloadAllBtn.style = `position: relative;top: 60px;align-items: center;display: flex;`;
  63. downloadAllBtn.classList.add("leftMenu");
  64. document.getElementById("leftMenu").append(selectBtn,downloadAllBtn,downloadBtn)
  65. //adding events
  66. images.forEach(image => {
  67. image.addEventListener('mouseenter', enterImg);
  68. image.addEventListener('mousemove', hoverImg);
  69. image.addEventListener('mouseleave', leaveImg);
  70. })
  71. selectBtn.addEventListener("click", () => {
  72. hidden = false
  73. document.querySelector(".headerMenu").click();
  74. document.querySelectorAll(".downloadInput").forEach(el => {el.classList.remove("inputHidden");el.classList.add("inputShowen")});
  75. })
  76. downloadBtn.addEventListener("click",() => {
  77. document.querySelector(".headerMenu").click();
  78. downloaded = 0;
  79. collIndex = 0;
  80. let buttons = document.querySelectorAll(".downloadInput:checked");
  81. if (buttons.length === 0) return;
  82. buttons.forEach(button => collectionsToDownload.push(...collections.filter(el => el.id === +button.value)))
  83. buttons.forEach(button => {button.checked = false})
  84. if (hidden === true) document.querySelectorAll(".downloadInput").forEach(el => {el.classList.add("inputHidden");el.classList.remove("inputShowen")});
  85. let downloading = setInterval(function() {
  86. if (collIndex === collectionsToDownload.length) {
  87. clearInterval(downloading);
  88. collIndex = 0;
  89. }
  90. else {
  91. let collection = collectionsToDownload[collIndex].images,
  92. id = collectionsToDownload[collIndex].id;
  93. downloadColl(collection,id)
  94. collIndex++;
  95. }
  96. }, 1000);
  97. })
  98. downloadAllBtn.addEventListener("click",() => {
  99. document.querySelector(".headerMenu").click();
  100. downloaded = 0;
  101. collIndex = 0;
  102. if ((collections.length === images.length) === false) return alert(`Wait until you see all the Checkmarks '✔' next to the number of views. Available ${collections.length} out of ${images.length}`);
  103. else {
  104. collectionsToDownload = collections
  105. let downloading = setInterval(function() {
  106. if (collIndex === collectionsToDownload.length) {
  107. clearInterval(downloading);
  108. collIndex = 0;
  109. }
  110. else {
  111. let collection = collectionsToDownload[collIndex].images,
  112. id = collectionsToDownload[collIndex].id;
  113. downloadColl(collection,id)
  114. collIndex++;
  115. }
  116. }, 1000);
  117. }
  118. })
  119. //scraping image from links
  120. document.querySelectorAll(".itemBox a").forEach((link,index) => {
  121. let xhr = new XMLHttpRequest();
  122. xhr.responseType = "document"
  123. collectionsList.push({collId: +link.href.match(/view_([0-9]+)_/)[1], id: index})
  124. xhr.addEventListener("load", function() {
  125. if (xhr.status === 200) {
  126. let request = xhr.response,
  127. output = {id: +xhr.responseURL.match(/view_([0-9]+)_/)[1], images: []}
  128. request.querySelectorAll(".lazyload.showMiniImage").forEach(el => output.images.push(el.dataset.src))
  129. collections.push(output)
  130. let collId = collectionsList.filter(el => el.collId === output.id);
  131. if (collId.length === 1) document.querySelectorAll('.viewCountBox')[collId[0].id].innerHTML = `<input type="checkbox" class="downloadInput ${hidden === true? "inputHidden" : "inputShowen"}" value="${output.id}"> ${document.querySelectorAll('.viewCountBox')[collId[0].id].innerHTML}`
  132. if (collections.length === images.length) {collections.sort((a, b) => a.id < b.id ? 1 : -1); console.log(collections)}
  133. }
  134. });
  135. xhr.open("GET", link.href, true);
  136. xhr.send();
  137. })
  138. //functions
  139. function downloadColl(array,collectionTitle) {
  140. downloaded = 0;
  141. let zip = new JSZip();
  142. array.map((el, index) => {
  143. let xhr = new XMLHttpRequest();
  144. xhr.open('GET', `https://asiansister.com/${el.slice(0,-6)}.jpg`, true);
  145. xhr.responseType = 'arraybuffer';
  146. xhr.onload = function(e) {
  147. if (this.status !== 200) return;
  148. zip.file(`image_${index + 1}.jpg`, xhr.response);
  149. downloaded++;
  150. if (downloaded === array.length) {
  151. zip.generateAsync({type:"blob"})
  152. .then(function(content) {
  153. saveAs(content, `${collectionTitle}.zip`);
  154. });
  155. }
  156. }
  157. xhr.send();
  158. })
  159. }
  160. function hoverImg(e) {
  161. let distance = e.clientY - this.y, //calculating distance from top
  162. id = collections.findIndex(el => el.id === currentId);
  163. if (id === -1) return;
  164. let step = this.height / collections[id].images.length, //calculating amount of steps
  165. target = Math.round(distance/step); //pointing single image
  166. if (collections.length > 0 && imageQuality === "hq") this.src = `https://asiansister.com/${collections[id].images[target].slice(0,-6)}.jpg`
  167. if (collections.length > 0 && imageQuality === "lq") this.src = `https://asiansister.com/${collections[id].images[target]}`
  168. }
  169. function enterImg() {
  170. currentId = +this.parentElement.parentElement.href.match(/view_([0-9]+)_/)[1]
  171. }
  172. function leaveImg() {
  173. currentId = 0;
  174. this.src = this.dataset.src;
  175. }
  176. })();