Embedded Image Viewer

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

目前为 2023-02-08 提交的版本。查看 最新版本

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