- // ==UserScript==
- // @name Embedded Image Viewer
- // @namespace Violentmonkey Scripts
- // @match *://*.furaffinity.net/*
- // @grant none
- // @version 1.4.1
- // @author Midori Dragon
- // @description Embedds the clicked Image on the Current Site, so you can view it without loading the submission Page
- // @icon https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png?v2
- // @homepageURL https://gf.qytechs.cn/de/scripts/458971-embedded-image-viewer
- // @supportURL https://gf.qytechs.cn/de/scripts/458971-embedded-image-viewer/feedback
- // @license MIT
- // ==/UserScript==
-
- // jshint esversion: 8
-
- //User Options:
- const loadingSpinSpeed = 100; //Sets the spinning speed of the loading animation in milliseconds
- const matchList = ['net/browse', 'net/gallery', 'net/search', 'net/favorites', 'net/controls/favorites', 'net/controls/submissions', 'net/msg/submissions' ];
-
- if (!matchList.some(x => window.location.toString().includes(x)))
- return;
-
- let color = "color: blue";
- if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
- color = "color: aqua";
- console.info(`%cRunning: ${GM_info.script.name} v${GM_info.script.version} (Settings: "SpinSpeed = ${loadingSpinSpeed}")`, color);
-
- let isShowing = false;
- let notClosingElemsArr = [];
-
- document.addEventListener("click", function(event) {
- if (isShowing && !notClosingElemsArr.includes(event.target.id)) {
- event.preventDefault();
- document.getElementById("embeddedElem").remove();
- isShowing = false;
- }
- });
-
- addEmbedded();
-
- window.updateEmbedded = function() { addEmbedded(); };
-
- async function addEmbedded() {
- for (const figure of document.querySelectorAll('figure:not([embedded])')) {
- figure.setAttribute('embedded', true);
- figure.addEventListener("click", function(event) {
- if (!event.ctrlKey && !event.target.id.includes("favbutton") && event.target.type != "checkbox") {
- if (event.target.href)
- return;
- else
- event.preventDefault();
- if (!isShowing)
- showImage(figure);
- }
- });
- }
- }
-
- async function showImage(figure) {
- const ddmenu = document.getElementById("ddmenu");
- const imageID = figure.id.substring(figure.id.indexOf("-") + 1);
- const favdoc = await getHTML("https://www.furaffinity.net/view/" + imageID);
-
- await createElements(ddmenu, favdoc, imageID, figure);
-
- isShowing = true;
- }
-
- async function createElements(ddmenu, favdoc, imageID, figure) {
- const margin = 20;
-
- let embeddedElem = document.createElement("div");
- embeddedElem.id = "embeddedElem";
- embeddedElem.style.position = "fixed";
- embeddedElem.style.zIndex = "999999";
- embeddedElem.style.width = window.innerWidth + "px";
- embeddedElem.style.height = window.innerHeight + "px";
- embeddedElem.style.background = "rgba(30,33,38,.65)";
-
- let backgroundElem = document.createElement("div");
- backgroundElem.id = "embeddedBackgroundElem";
- notClosingElemsArr.push(backgroundElem.id);
- backgroundElem.style.position = "fixed";
- backgroundElem.style.display = "flex";
- backgroundElem.style.flexDirection = "column";
- backgroundElem.style.left = "50%";
- backgroundElem.style.transform = "translate(-50%, 0%)";
- backgroundElem.style.marginTop = margin + "px";
- backgroundElem.style.padding = margin + "px";
- backgroundElem.style.background = "rgba(30,33,38,.90)";
- backgroundElem.style.borderRadius = "10px";
-
- let submissionContainer = document.createElement("a");
- submissionContainer.id = "embeddedSubmissionContainer";
- notClosingElemsArr.push(submissionContainer.id);
- submissionContainer.href = favdoc.querySelector('meta[property="og:url"]').content;
-
- let submissionImg = favdoc.getElementById("submissionImg");
- submissionImg.id = "embeddedSubmissionImg";
- notClosingElemsArr.push(submissionImg.id);
- submissionImg.removeAttribute("data-fullview-src");
- submissionImg.removeAttribute("data-preview-src");
- submissionImg.style.maxWidth = "inherit";
- submissionImg.style.maxHeight = "inherit";
- submissionImg.style.maxWidth = window.innerWidth - margin * 2 + "px";
- submissionImg.style.maxHeight = window.innerHeight - ddmenu.clientHeight - 38 * 2 - margin * 2 - 100 + "px";
- submissionImg.style.borderRadius = "10px";
- submissionContainer.appendChild(submissionImg);
-
- backgroundElem.appendChild(submissionContainer);
-
- let buttonsContainer = document.createElement("div");
- buttonsContainer.id = "embeddedButtonsContainer";
- notClosingElemsArr.push(buttonsContainer.id);
- buttonsContainer.style.marginTop = "20px";
- buttonsContainer.style.marginLeft = "20px";
- buttonsContainer.style.marginRight = "20px";
-
- let embeddedFavButton = document.createElement("a");
- embeddedFavButton.id = "embeddedFavButton";
- notClosingElemsArr.push(embeddedFavButton.id);
- embeddedFavButton.type = "button";
- embeddedFavButton.className = "button standard mobile-fix";
-
- let favlink;
- //Fast Favoriter 2 integration <start>
- const favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
- if (favButton) {
- favlink = favButton.getAttribute("favlink");
- console.log(favlink);
- embeddedFavButton.textContent = favButton.textContent;
- } else { //Fast Favoriter 2 integration <end>
- favlink = await getfavlink(favdoc);
- if (favlink.includes("unfav"))
- embeddedFavButton.textContent = "-Fav";
- else
- embeddedFavButton.textContent = "+Fav";
- }
- embeddedFavButton.style.marginLeft = "4px";
- embeddedFavButton.style.marginRight = "4px";
- embeddedFavButton.onclick = function() {
- let erotation = rotateText(embeddedFavButton);
- console.log(favlink)
- favImage(figure, favlink, '', erotation);
- };
- buttonsContainer.appendChild(embeddedFavButton);
-
- let downloadButton = document.createElement("a");
- downloadButton.id = "embeddedDownloadButton";
- notClosingElemsArr.push(downloadButton.id);
- downloadButton.type = "button";
- downloadButton.className = "button standard mobile-fix";
- downloadButton.textContent = "Download";
- downloadButton.style.marginLeft = "4px";
- downloadButton.style.marginRight = "4px";
- const downloadLink = await getDownloadLink(favdoc);
- downloadButton.href = downloadLink;
- downloadButton.download = downloadLink.substring(downloadLink.lastIndexOf("/") + 1);
- buttonsContainer.appendChild(downloadButton);
-
- let closeButton = document.createElement("a");
- closeButton.id = "embeddedCloseButton";
- notClosingElemsArr.push(closeButton.id);
- closeButton.type = "button";
- closeButton.className = "button standard mobile-fix";
- closeButton.textContent = "Close";
- closeButton.style.marginLeft = "4px";
- closeButton.style.marginRight = "4px";
- closeButton.onclick = function() {
- ddmenu.removeChild(embeddedElem);
- isShowing = false;
- };
- buttonsContainer.appendChild(closeButton);
-
- backgroundElem.appendChild(buttonsContainer);
-
- embeddedElem.appendChild(backgroundElem);
-
- ddmenu.appendChild(embeddedElem);
- }
-
- async function favImage(figure, favlink, rotation, erotation) {
- if (!figure)
- return;
-
- let footer = document.getElementById("footer");
- let iframe = document.createElement("iframe");
- iframe.id = "favIFrame";
- iframe.src = favlink;
- iframe.style.display = "none";
- iframe.addEventListener("load", async function() {
- let favdoc = iframe.contentDocument;
- footer.removeChild(iframe);
- let imageLink = figure.childNodes[0].childNodes[0].childNodes[0].href;
- favlink = await getfavlink(favdoc);
- if (!favlink) {
- checkFavLinkMissingReason(figure, favdoc);
- return;
- }
- changeFavButtonLink(favlink, figure, rotation, erotation);
- });
- footer.appendChild(iframe);
- }
-
- async function checkFavLinkMissingReason(figure, favdoc) {
- favOnError(figure);
- let blocked = favdoc.getElementById("standardpage").querySelector('div[class="redirect-message"]');
- if (blocked && blocked.textContent.includes("blocked"))
- alert(blocked.textContent);
- }
-
- async function favOnError(figure) {
- let embeddedFavButton = document.getElementById("embeddedFavButton");
- if (embeddedFavButton)
- embeddedFavButton.textContent = "x";
-
- //Fast Favoriter 2 integration <start>
- let favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
- if (favButton)
- favButton.textContent = "x";
- //Fast Favoriter 2 integration <end>
- }
-
- async function changeFavButtonLink(favlink, figure, rotation, erotation) {
- let embeddedFavButton = document.getElementById("embeddedFavButton");
- if (embeddedFavButton) {
- erotation();
- if (favlink.includes("unfav"))
- embeddedFavButton.textContent = "-Fav";
- else
- embeddedFavButton.textContent = "+Fav";
- embeddedFavButton.onclick = function() {
- erotation = rotateText(embeddedFavButton);
- favImage(figure, favlink, rotation, erotation);
- };
- }
-
- //Fast Favoriter 2 integration <start>
- let favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
- if (favButton) {
- if (rotation)
- rotation();
- if (favlink.includes("unfav"))
- favButton.textContent = "-Fav";
- else
- favButton.textContent = "+Fav";
- favButton.onclick = function() {
- rotation = rotateText(favButton);
- favImage(figure, favlink, rotation, erotation);
- };
- }
- //Fast Favoriter 2 integration <end>
- }
-
- function rotateText(element) {
- let isRotating = true;
- const characters = [ "◜", "◠", "◝", "◞", "◡", "◟" ];
- let index = 0;
-
- function update() {
- if (!isRotating) return;
- element.textContent = characters[index % characters.length];
- index++;
- setTimeout(update, loadingSpinSpeed);
- }
- if (!isRotating) return;
- update();
-
- return function stopRotation() {
- isRotating = false;
- };
- }
-
- async function getfavlink(subdoc) {
- let buttons = subdoc.querySelectorAll('a[class="button standard mobile-fix"]');
- for (const button of buttons)
- if (button.textContent.includes("Fav") && button.textContent.length <= 4)
- return button.href;
- }
-
- async function getDownloadLink(subdoc) {
- let buttons = subdoc.querySelectorAll('a[class="button standard mobile-fix"]');
- for (const button of buttons)
- if (button.textContent.includes("Download"))
- return button.href;
- }
-
- async function getHTML(url) {
- try {
- const response = await fetch(url);
- const html = await response.text();
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, "text/html");
- return doc;
- } catch (error) {
- console.error(error);
- }
- }