Fanvue Image Download

directly download images from fanvue

  1. // ==UserScript==
  2. // @name Fanvue Image Download
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description directly download images from fanvue
  6. // @author x.scape
  7. // @match https://www.fanvue.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=fanvue.com
  9. // @grant none
  10. // @license Apache License, 2.0
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. const ADDON_NAME = "tpmk_fanvue_img_dl";
  16.  
  17. function createTailwindScript() {
  18. let script = document.createElement("script");
  19. script.setAttribute("src", "https://cdn.tailwindcss.com");
  20. return script;
  21. }
  22. document.querySelector("head").append(createTailwindScript());
  23.  
  24. function elementVisible(elem) {
  25. const { top, left, bottom, right } = elem.getBoundingClientRect();
  26. const { innerHeight, innerWidth } = window;
  27. return ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) && ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth));
  28. }
  29.  
  30. function getLoadedImages() {
  31. return Array.from(document.querySelectorAll("img.MuiBox-root"));
  32. }
  33.  
  34. function reduceLoadedImages() {
  35. let imgList = getLoadedImages();
  36. let loaded = [];
  37. imgList.forEach((img) => {
  38. if (elementVisible(img) && !(img.classList.contains(".mui-14baudc")))
  39. loaded.push(img);
  40. });
  41. return loaded;
  42. }
  43.  
  44. function downloadBtn() {
  45. let btn = document.createElement("button");
  46. btn.setAttribute("type", "button");
  47. btn.setAttribute("class", "absolute top-4 left-4 backdrop-filter backdrop-blur-sm bg-opacity-10 text-white font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2");
  48. btn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" /></svg>';
  49. return btn;
  50. }
  51.  
  52. async function download(url, profile) {
  53. const image = await fetch(url);
  54. const imageBlob = await image.blob();
  55. const imageURL = URL.createObjectURL(imageBlob);
  56.  
  57. const link = document.createElement("a");
  58. link.href = imageURL;
  59. link.download = `${profile}_-_${Date.now()}`;
  60. link.target = "_blank";
  61.  
  62. document.body.appendChild(link);
  63. link.click();
  64. document.body.removeChild(link);
  65. }
  66.  
  67. function getImageSource(sourceSet) {
  68. return sourceSet.srcset.split("1x, ")[1].split(" 2x")[0];
  69. }
  70.  
  71. document.addEventListener("scrollend", () => {
  72. let visibleImages = reduceLoadedImages();
  73. visibleImages.forEach((img) => {
  74. if (!img.parentElement.classList.contains("relative")) {
  75. let btn = downloadBtn();
  76. img.parentElement.classList.add("relative");
  77. img.parentElement.append(btn);
  78. btn.addEventListener("click", (event) => {
  79. console.log(event.target.parentElement.closest("div.MuiBox-root"), event.target.parentElement.closest("li.slide"));
  80. let parent = event.target.parentElement.closest("li.slide") != null ? event.target.parentElement.closest("li.slide") : event.target.parentElement.closest("div.MuiBox-root");
  81. console.log(parent);
  82. let img = parent.querySelector("img");
  83. let src = getImageSource(img);
  84. download(src, document.querySelector("#profileHeader > section > div.MuiBox-root.mui-1kpdnj > p").textContent);
  85. });
  86. }
  87. });
  88. });
  89. })();