// ==UserScript==
// @name Embedded Image Viewer
// @namespace Violentmonkey Scripts
// @match *://*.furaffinity.net/*
// @grant none
// @version 1.4
// @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://greasyfork.org/de/scripts/458971-embedded-image-viewer
// @supportURL https://greasyfork.org/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;
console.info('%cRunning: Embedded Image Viewer', 'color: blue');
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);
}
}