Embedded Image Viewer

Embedds the clicked Image on the Current Site, so you can view it without loading the submission Page

目前為 2023-05-15 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Embedded Image Viewer
  3. // @namespace Violentmonkey Scripts
  4. // @match *://*.furaffinity.net/*
  5. // @grant none
  6. // @version 1.4
  7. // @author Midori Dragon
  8. // @description Embedds the clicked Image on the Current Site, so you can view it without loading the submission Page
  9. // @icon https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png?v2
  10. // @homepageURL https://greasyfork.org/de/scripts/458971-embedded-image-viewer
  11. // @supportURL https://greasyfork.org/de/scripts/458971-embedded-image-viewer/feedback
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. // jshint esversion: 8
  16.  
  17. //User Options:
  18. const loadingSpinSpeed = 100; //Sets the spinning speed of the loading animation in milliseconds
  19. const matchList = ['net/browse', 'net/gallery', 'net/search', 'net/favorites', 'net/controls/favorites', 'net/controls/submissions', 'net/msg/submissions' ];
  20.  
  21. if (!matchList.some(x => window.location.toString().includes(x)))
  22. return;
  23.  
  24. console.info('%cRunning: Embedded Image Viewer', 'color: blue');
  25.  
  26. let isShowing = false;
  27. let notClosingElemsArr = [];
  28.  
  29. document.addEventListener("click", function(event) {
  30. if (isShowing && !notClosingElemsArr.includes(event.target.id)) {
  31. event.preventDefault();
  32. document.getElementById("embeddedElem").remove();
  33. isShowing = false;
  34. }
  35. });
  36.  
  37. addEmbedded();
  38.  
  39. window.updateEmbedded = function() { addEmbedded(); };
  40.  
  41. async function addEmbedded() {
  42. for (const figure of document.querySelectorAll('figure:not([embedded])')) {
  43. figure.setAttribute('embedded', true);
  44. figure.addEventListener("click", function(event) {
  45. if (!event.ctrlKey && !event.target.id.includes("favbutton") && event.target.type != "checkbox") {
  46. if (event.target.href)
  47. return;
  48. else
  49. event.preventDefault();
  50. if (!isShowing)
  51. showImage(figure);
  52. }
  53. });
  54. }
  55. }
  56.  
  57. async function showImage(figure) {
  58. const ddmenu = document.getElementById("ddmenu");
  59. const imageID = figure.id.substring(figure.id.indexOf("-") + 1);
  60. const favdoc = await getHTML("https://www.furaffinity.net/view/" + imageID);
  61.  
  62. await createElements(ddmenu, favdoc, imageID, figure);
  63.  
  64. isShowing = true;
  65. }
  66.  
  67. async function createElements(ddmenu, favdoc, imageID, figure) {
  68. const margin = 20;
  69.  
  70. let embeddedElem = document.createElement("div");
  71. embeddedElem.id = "embeddedElem";
  72. embeddedElem.style.position = "fixed";
  73. embeddedElem.style.zIndex = "999999";
  74. embeddedElem.style.width = window.innerWidth + "px";
  75. embeddedElem.style.height = window.innerHeight + "px";
  76. embeddedElem.style.background = "rgba(30,33,38,.65)";
  77.  
  78. let backgroundElem = document.createElement("div");
  79. backgroundElem.id = "embeddedBackgroundElem";
  80. notClosingElemsArr.push(backgroundElem.id);
  81. backgroundElem.style.position = "fixed";
  82. backgroundElem.style.display = "flex";
  83. backgroundElem.style.flexDirection = "column";
  84. backgroundElem.style.left = "50%";
  85. backgroundElem.style.transform = "translate(-50%, 0%)";
  86. backgroundElem.style.marginTop = margin + "px";
  87. backgroundElem.style.padding = margin + "px";
  88. backgroundElem.style.background = "rgba(30,33,38,.90)";
  89. backgroundElem.style.borderRadius = "10px";
  90.  
  91. let submissionContainer = document.createElement("a");
  92. submissionContainer.id = "embeddedSubmissionContainer";
  93. notClosingElemsArr.push(submissionContainer.id);
  94. submissionContainer.href = favdoc.querySelector('meta[property="og:url"]').content;
  95.  
  96. let submissionImg = favdoc.getElementById("submissionImg");
  97. submissionImg.id = "embeddedSubmissionImg";
  98. notClosingElemsArr.push(submissionImg.id);
  99. submissionImg.removeAttribute("data-fullview-src");
  100. submissionImg.removeAttribute("data-preview-src");
  101. submissionImg.style.maxWidth = "inherit";
  102. submissionImg.style.maxHeight = "inherit";
  103. submissionImg.style.maxWidth = window.innerWidth - margin * 2 + "px";
  104. submissionImg.style.maxHeight = window.innerHeight - ddmenu.clientHeight - 38 * 2 - margin * 2 - 100 + "px";
  105. submissionImg.style.borderRadius = "10px";
  106. submissionContainer.appendChild(submissionImg);
  107.  
  108. backgroundElem.appendChild(submissionContainer);
  109.  
  110. let buttonsContainer = document.createElement("div");
  111. buttonsContainer.id = "embeddedButtonsContainer";
  112. notClosingElemsArr.push(buttonsContainer.id);
  113. buttonsContainer.style.marginTop = "20px";
  114. buttonsContainer.style.marginLeft = "20px";
  115. buttonsContainer.style.marginRight = "20px";
  116.  
  117. let embeddedFavButton = document.createElement("a");
  118. embeddedFavButton.id = "embeddedFavButton";
  119. notClosingElemsArr.push(embeddedFavButton.id);
  120. embeddedFavButton.type = "button";
  121. embeddedFavButton.className = "button standard mobile-fix";
  122.  
  123. let favlink;
  124. //Fast Favoriter 2 integration <start>
  125. const favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
  126. if (favButton) {
  127. favlink = favButton.getAttribute("favlink");
  128. console.log(favlink);
  129. embeddedFavButton.textContent = favButton.textContent;
  130. } else { //Fast Favoriter 2 integration <end>
  131. favlink = await getfavlink(favdoc);
  132. if (favlink.includes("unfav"))
  133. embeddedFavButton.textContent = "-Fav";
  134. else
  135. embeddedFavButton.textContent = "+Fav";
  136. }
  137. embeddedFavButton.style.marginLeft = "4px";
  138. embeddedFavButton.style.marginRight = "4px";
  139. embeddedFavButton.onclick = function() {
  140. let erotation = rotateText(embeddedFavButton);
  141. console.log(favlink)
  142. favImage(figure, favlink, '', erotation);
  143. };
  144. buttonsContainer.appendChild(embeddedFavButton);
  145.  
  146. let downloadButton = document.createElement("a");
  147. downloadButton.id = "embeddedDownloadButton";
  148. notClosingElemsArr.push(downloadButton.id);
  149. downloadButton.type = "button";
  150. downloadButton.className = "button standard mobile-fix";
  151. downloadButton.textContent = "Download";
  152. downloadButton.style.marginLeft = "4px";
  153. downloadButton.style.marginRight = "4px";
  154. const downloadLink = await getDownloadLink(favdoc);
  155. downloadButton.href = downloadLink;
  156. downloadButton.download = downloadLink.substring(downloadLink.lastIndexOf("/") + 1);
  157. buttonsContainer.appendChild(downloadButton);
  158.  
  159. let closeButton = document.createElement("a");
  160. closeButton.id = "embeddedCloseButton";
  161. notClosingElemsArr.push(closeButton.id);
  162. closeButton.type = "button";
  163. closeButton.className = "button standard mobile-fix";
  164. closeButton.textContent = "Close";
  165. closeButton.style.marginLeft = "4px";
  166. closeButton.style.marginRight = "4px";
  167. closeButton.onclick = function() {
  168. ddmenu.removeChild(embeddedElem);
  169. isShowing = false;
  170. };
  171. buttonsContainer.appendChild(closeButton);
  172.  
  173. backgroundElem.appendChild(buttonsContainer);
  174.  
  175. embeddedElem.appendChild(backgroundElem);
  176.  
  177. ddmenu.appendChild(embeddedElem);
  178. }
  179.  
  180. async function favImage(figure, favlink, rotation, erotation) {
  181. if (!figure)
  182. return;
  183.  
  184. let footer = document.getElementById("footer");
  185. let iframe = document.createElement("iframe");
  186. iframe.id = "favIFrame";
  187. iframe.src = favlink;
  188. iframe.style.display = "none";
  189. iframe.addEventListener("load", async function() {
  190. let favdoc = iframe.contentDocument;
  191. footer.removeChild(iframe);
  192. let imageLink = figure.childNodes[0].childNodes[0].childNodes[0].href;
  193. favlink = await getfavlink(favdoc);
  194. if (!favlink) {
  195. checkFavLinkMissingReason(figure, favdoc);
  196. return;
  197. }
  198. changeFavButtonLink(favlink, figure, rotation, erotation);
  199. });
  200. footer.appendChild(iframe);
  201. }
  202.  
  203. async function checkFavLinkMissingReason(figure, favdoc) {
  204. favOnError(figure);
  205. let blocked = favdoc.getElementById("standardpage").querySelector('div[class="redirect-message"]');
  206. if (blocked && blocked.textContent.includes("blocked"))
  207. alert(blocked.textContent);
  208. }
  209.  
  210. async function favOnError(figure) {
  211. let embeddedFavButton = document.getElementById("embeddedFavButton");
  212. if (embeddedFavButton)
  213. embeddedFavButton.textContent = "x";
  214.  
  215. //Fast Favoriter 2 integration <start>
  216. let favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
  217. if (favButton)
  218. favButton.textContent = "x";
  219. //Fast Favoriter 2 integration <end>
  220. }
  221.  
  222. async function changeFavButtonLink(favlink, figure, rotation, erotation) {
  223. let embeddedFavButton = document.getElementById("embeddedFavButton");
  224. if (embeddedFavButton) {
  225. erotation();
  226. if (favlink.includes("unfav"))
  227. embeddedFavButton.textContent = "-Fav";
  228. else
  229. embeddedFavButton.textContent = "+Fav";
  230. embeddedFavButton.onclick = function() {
  231. erotation = rotateText(embeddedFavButton);
  232. favImage(figure, favlink, rotation, erotation);
  233. };
  234. }
  235.  
  236. //Fast Favoriter 2 integration <start>
  237. let favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
  238. if (favButton) {
  239. if (rotation)
  240. rotation();
  241. if (favlink.includes("unfav"))
  242. favButton.textContent = "-Fav";
  243. else
  244. favButton.textContent = "+Fav";
  245. favButton.onclick = function() {
  246. rotation = rotateText(favButton);
  247. favImage(figure, favlink, rotation, erotation);
  248. };
  249. }
  250. //Fast Favoriter 2 integration <end>
  251. }
  252.  
  253. function rotateText(element) {
  254. let isRotating = true;
  255. const characters = [ "◜", "◠", "◝", "◞", "◡", "◟" ];
  256. let index = 0;
  257.  
  258. function update() {
  259. if (!isRotating) return;
  260. element.textContent = characters[index % characters.length];
  261. index++;
  262. setTimeout(update, loadingSpinSpeed);
  263. }
  264. if (!isRotating) return;
  265. update();
  266.  
  267. return function stopRotation() {
  268. isRotating = false;
  269. };
  270. }
  271.  
  272. async function getfavlink(subdoc) {
  273. let buttons = subdoc.querySelectorAll('a[class="button standard mobile-fix"]');
  274. for (const button of buttons)
  275. if (button.textContent.includes("Fav") && button.textContent.length <= 4)
  276. return button.href;
  277. }
  278.  
  279. async function getDownloadLink(subdoc) {
  280. let buttons = subdoc.querySelectorAll('a[class="button standard mobile-fix"]');
  281. for (const button of buttons)
  282. if (button.textContent.includes("Download"))
  283. return button.href;
  284. }
  285.  
  286. async function getHTML(url) {
  287. try {
  288. const response = await fetch(url);
  289. const html = await response.text();
  290. const parser = new DOMParser();
  291. const doc = parser.parseFromString(html, "text/html");
  292. return doc;
  293. } catch (error) {
  294. console.error(error);
  295. }
  296. }