Embedded Image Viewer

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

目前為 2024-01-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Embedded Image Viewer
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/*
// @require 	https://greatest.deepsurf.us/scripts/475041-furaffinity-custom-settings/code/Furaffinity-Custom-Settings.js
// @require     https://greatest.deepsurf.us/scripts/483952-furaffinity-request-helper/code/Furaffinity-Request-Helper.js
// @require		https://greatest.deepsurf.us/scripts/485153-furaffinity-loading-animations/code/Furaffinity-Loading-Animations.js
// @grant       none
// @version     2.0.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://greatest.deepsurf.us/de/scripts/458971-embedded-image-viewer
// @supportURL  https://greatest.deepsurf.us/de/scripts/458971-embedded-image-viewer/feedback
// @license     MIT
// ==/UserScript==

// jshint esversion: 8

const matchList = ['net/browse', 'net/gallery', 'net/search', 'net/favorites', 'net/scraps', 'net/controls/favorites', 'net/controls/submissions', 'net/msg/submissions', 'd.furaffinity.net'];

const isDFuraffinity = window.location.toString().includes("d.furaffinity.net");
const isDownloadImage = window.location.toString().includes("?eidownload");

if (isDFuraffinity) {
    if (isDownloadImage)
        downloadImage();
    return;
}

CustomSettings.name = "Extension Settings";
CustomSettings.provider = "Midori's Script Settings";
CustomSettings.headerName = `${GM_info.script.name} Settings`;
const preventInstantDownloadSetting = CustomSettings.newSetting("Prevent Instant Download", "Sets wether to instantly download the Image when the download Button is pressed.", SettingTypes.Boolean, "Prevent Instant Download", false);
const loadingSpinSpeedSetting = CustomSettings.newSetting("Fav Loading Animation", "Sets the spinning speed of the loading animation in milliseconds.", SettingTypes.Number, "", 100);
CustomSettings.loadSettings();

let color = "color: blue";
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
    color = "color: aqua";
if (window.location.toString().includes("?extension")) {
    console.info(`%cSettings: ${GM_info.script.name} v${GM_info.script.version}`, color);
    return;
}

if (!matchList.some(x => window.location.toString().includes(x)))
    return;

console.info(`%cRunning: ${GM_info.script.name} v${GM_info.script.version} ${CustomSettings.toString()}`, color);

const requestHelper = new FARequestHelper(2);

class EmbeddedImage {
    constructor(figure) {
        this.embeddedElem;
        this.backgroundElem;
        this.submissionContainer;
        this.submissionImg;
        this.buttonsContainer;
        this.favButton;
        this.downloadButton;
        this.closeButton;

        this._onRemoveAction;

        this.createStyle();
        this.createElements();

        this.loadingSpinner = new LoadingSpinner(this.submissionContainer);
	  	this.loadingSpinner.spinnerThickness = 6;
        this.loadingSpinner.visible = true;
        this.fillSubDocInfos(figure);
    }

    createStyle() {
        if (document.getElementById("embeddedStyle")) return;
        const style = document.createElement("style");
        style.id = "embeddedStyle";
        style.type = "text/css";
        style.innerHTML = `
            #embeddedElem {
                position: fixed;
				width: 100vw;
				height: 100vh;
				max-width: 1850px;
                z-index: 999999;
                background: rgba(30,33,38,.65);
            }
            #embeddedBackgroundElem {
                position: fixed;
                display: flex;
                flex-direction: column;
                left: 50%;
                transform: translate(-50%, 0%);
                margin-top: 20px;
                padding: 20px;
                background: rgba(30,33,38,.90);
                border-radius: 10px;
            }
            #embeddedSubmissionImg {
                max-width: inherit;
                max-height: inherit;
                border-radius: 10px;
            }
            #embeddedButtonsContainer {
                margin-top: 20px;
                margin-bottom: 20px;
                margin-left: 20px;
            }
            .embeddedButton {
                margin-left: 4px;
                margin-right: 4px;
            }
        `;
        document.head.appendChild(style);
    }

    onRemove(action) {
        this._onRemoveAction = action;
    }

    remove() {
        this.embeddedElem.parentNode.removeChild(this.embeddedElem);
        if (this._onRemoveAction)
            this._onRemoveAction();
    }

    createElements() {
        this.embeddedElem = document.createElement("div");
        this.embeddedElem.id = "embeddedElem";
        this.embeddedElem.onclick = (event) => {
		  	if (event.target == this.embeddedElem)
		  		this.remove();
		}

        this.backgroundElem = document.createElement("div");
        this.backgroundElem.id = "embeddedBackgroundElem";
        notClosingElemsArr.push(this.backgroundElem.id);;

        this.submissionContainer = document.createElement("a");
        this.submissionContainer.id = "embeddedSubmissionContainer";
        notClosingElemsArr.push(this.submissionContainer.id);

        this.backgroundElem.appendChild(this.submissionContainer);

        this.buttonsContainer = document.createElement("div");
        this.buttonsContainer.id = "embeddedButtonsContainer";
        notClosingElemsArr.push(this.buttonsContainer.id);

        this.favButton = document.createElement("a");
        this.favButton.id = "embeddedFavButton";
        notClosingElemsArr.push(this.favButton.id);
        this.favButton.type = "button";
        this.favButton.className = "embeddedButton button standard mobile-fix";
        this.favButton.textContent = "-";
        this.buttonsContainer.appendChild(this.favButton);

        this.downloadButton = document.createElement("a");
        this.downloadButton.id = "embeddedDownloadButton";
        notClosingElemsArr.push(this.downloadButton.id);
        this.downloadButton.type = "button";
        this.downloadButton.className = "embeddedButton button standard mobile-fix";
        this.downloadButton.textContent = "Download";
        this.downloadButton.target = "_blank";
        this.buttonsContainer.appendChild(this.downloadButton);

        this.closeButton = document.createElement("a");
        this.closeButton.id = "embeddedCloseButton";
        notClosingElemsArr.push(this.closeButton.id);
        this.closeButton.type = "button";
        this.closeButton.className = "embeddedButton button standard mobile-fix";
        this.closeButton.textContent = "Close";
        this.closeButton.onclick = () => this.remove();
        this.buttonsContainer.appendChild(this.closeButton);

        this.backgroundElem.appendChild(this.buttonsContainer);

        this.embeddedElem.appendChild(this.backgroundElem);

        const ddmenu = document.getElementById("ddmenu");
        ddmenu.appendChild(this.embeddedElem);
    }

    async fillSubDocInfos(figure) {
        const sid = figure.id.split("-")[1];
        const ddmenu = document.getElementById("ddmenu");
        const doc = await requestHelper.SubmissionRequests.getSubmissionPage(sid);
        if (this.loadingSpinner)
            this.loadingSpinner.visible = false;
        if (doc) {
            this.submissionImg = doc.getElementById("submissionImg");
            this.submissionImg.style.maxWidth = window.innerWidth - 20 * 2 + "px";
            this.submissionImg.style.maxHeight = window.innerHeight - ddmenu.clientHeight - 38 * 2 - 20 * 2 - 100 + "px";
            this.submissionContainer.appendChild(this.submissionImg);
            this.submissionContainer.href = doc.querySelector('meta[property="og:url"]').content;

            const result = getFavKey(doc);
            this.favButton.textContent = result.isFav ? "+Fav" : "-Fav";
            this.favButton.setAttribute("isFav", result.isFav);
            this.favButton.setAttribute("key", result.favKey);
            this.favButton.onclick = () => this.doFavRequest(sid);

            this.downloadButton.href = this.submissionImg.src + "?eidownload";
        }
    }

    async doFavRequest(sid) {
        const loadingTextSpinner = new LoadingTextSpinner(this.favButton);
        loadingTextSpinner.visible = true;
        let favKey = this.favButton.getAttribute("key");
        let isFav = this.favButton.getAttribute("isFav");
        if (isFav == "true") {
            favKey = await requestHelper.SubmissionRequests.favSubmission(sid, favKey);
            loadingTextSpinner.visible = false;
            if (favKey) {
                this.favButton.setAttribute("key", favKey);
                isFav = false;
                this.favButton.setAttribute("isFav", isFav);
                this.favButton.textContent = "-Fav";
            } else {
                this.favButton.textContent = "x";
                setTimeout(() => this.favButton.textContent = "+Fav", 1000);
            }
        } else {
            favKey = await requestHelper.SubmissionRequests.unfavSubmission(sid, favKey);
            loadingTextSpinner.visible = false;
            if (favKey) {
                this.favButton.setAttribute("key", favKey);
                isFav = true;
                this.favButton.setAttribute("isFav", isFav);
                this.favButton.textContent = "+Fav";
            } else {
                this.favButton.textContent = "x";
                setTimeout(() => this.favButton.textContent = "-Fav", 1000);
            }
        }
    }
}

function getFavKey(doc) {
    const columnPage = doc.getElementById("columnpage");
    const navbar = columnPage.querySelector('div[class*="favorite-nav"');
    const buttons = navbar.querySelectorAll('a[class*="button"][href]');
    let favButton;
    for (const button of buttons) {
        if (button.textContent.toLowerCase().includes("fav"))
            favButton = button;
    }

    if (favButton) {
        const favKey = favButton.href.split("?key=")[1];
        const isFav = !favButton.href.toLowerCase().includes("unfav");
        return { favKey, isFav };
    }
}

let isShowing = false;
let notClosingElemsArr = [];
let embeddedImage;

addEmbedded();
window.updateEmbedded = 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) {
    isShowing = true;
    embeddedImage = new EmbeddedImage(figure);
    embeddedImage.onRemove(() => {
        embeddedImage = null;
        isShowing = false;
    });
}

function downloadImage() {
    console.log("Embedded Image Viewer downloading Image...");
    let url = window.location.toString();
    if (url.includes("?")) {
        const parts = url.split('?');
        url = parts[0];
    }
    const download = document.createElement('a');
    download.href = url;
    download.download = url.substring(url.lastIndexOf("/") + 1);
    download.style.display = 'none';
    document.body.appendChild(download);
    download.click();
    document.body.removeChild(download);

    window.close();
}