Embedded Image Viewer

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

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

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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址