Embedded Image Viewer

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

Versión del día 08/02/2023. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name        Embedded Image Viewer
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/browse/*
// @match       *://*.furaffinity.net/gallery/*
// @match       *://*.furaffinity.net/search/*
// @match       *://*.furaffinity.net/favorites/*
// @match       *://*.furaffinity.net/controls/favorites/*
// @match       *://*.furaffinity.net/controls/submissions/*
// @match       *://*.furaffinity.net/msg/submissions/*
// @exclude-match *://*.furaffinity.net/view/*
// @grant       none
// @version     1.2
// @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
// @license     MIT
// ==/UserScript==

// jshint esversion: 8

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;
  }
});

for (const figure of document.getElementsByTagName("figure")) {
  figure.addEventListener("click", function(event) {
    if (!event.ctrlKey && !event.target.id.includes("favbutton")) {
      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");
    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() {
    embeddedFavButton.textContent = "...";
    favImage(figure, favlink);
  };
  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) {
  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);
  });
  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) {
  let embeddedFavButton = document.getElementById("embeddedFavButton");
  if (favlink.includes("unfav"))
    embeddedFavButton.textContent = "-Fav";
  else
    embeddedFavButton.textContent = "+Fav";
  embeddedFavButton.onclick = function() {
    embeddedFavButton.textContent = "...";
    favImage(figure, favlink);
  };

  //Fast Favoriter 2 integration <start>
  let favButton = figure.querySelector('[type="button"][class="button standard mobile-fix"]');
  if (favButton) {
    if (favlink.includes("unfav"))
      favButton.textContent = "-Fav";
    else
      favButton.textContent = "+Fav";
    favButton.onclick = function() {
      favButton.textContent = "...";
      favImage(figure, favlink);
    };
  }
  //Fast Favoriter 2 integration <end>
}

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);
  }
}