Instagram 隐藏图片

调整 Instagram 图片的透明度。

当前为 2020-05-28 提交的版本,查看 最新版本

// ==UserScript==
// @name                Instagram: Hide Image
// @name:zh-TW          Instagram 隱藏圖片
// @name:zh-CN          Instagram 隐藏图片
// @name:ja             Instagram 画像を非表示
// @name:ko             Instagram 이미지 숨기기
// @name:ru             Instagram Скрыть изображение
// @version             1.0.2
// @description         Make Instagram Images Opacity Lower.
// @description:zh-TW   調整 Instagram 圖片的透明度。
// @description:zh-CN   调整 Instagram 图片的透明度。
// @description:ja      Instagram 画像の不透明度を低くします。
// @description:ko      Instagram 이미지 불투명도를 낮추십시오.
// @description:ru      Уменьшите непрозрачность изображений в Instagram.
// @author              Hayao-Gai
// @namespace           https://github.com/HayaoGai
// @icon                https://i.imgur.com/obCmlr9.png
// @match               https://www.instagram.com*
// @grant               GM_getValue
// @grant               GM_setValue
// ==/UserScript==

/* jshint esversion: 6 */

(function() {
    'use strict';

    // icons made by https://www.flaticon.com/authors/pixel-perfect
    const iconOn = `<svg width="35" height="35" viewBox="0 -107 512 512"><path d="m362.667969 298.667969h-213.335938c-82.34375 0-149.332031-67.007813-149.332031-149.335938 0-82.324219 66.988281-149.332031 149.332031-149.332031h213.335938c82.34375 0 149.332031 67.007812 149.332031 149.332031 0 82.328125-66.988281 149.335938-149.332031 149.335938zm-213.335938-266.667969c-64.703125 0-117.332031 52.652344-117.332031 117.332031 0 64.683594 52.628906 117.335938 117.332031 117.335938h213.335938c64.703125 0 117.332031-52.652344 117.332031-117.335938 0-64.679687-52.628906-117.332031-117.332031-117.332031zm0 0"/><path d="m362.667969 234.667969c-47.0625 0-85.335938-38.273438-85.335938-85.335938 0-47.058593 38.273438-85.332031 85.335938-85.332031 47.058593 0 85.332031 38.273438 85.332031 85.332031 0 47.0625-38.273438 85.335938-85.332031 85.335938zm0-138.667969c-29.398438 0-53.335938 23.914062-53.335938 53.332031 0 29.421875 23.9375 53.335938 53.335938 53.335938 29.394531 0 53.332031-23.914063 53.332031-53.335938 0-29.417969-23.9375-53.332031-53.332031-53.332031zm0 0"/></svg>`;
    const iconOff = `<svg width="35" height="35" viewBox="0 -107 512 512"><path d="m362.667969 0h-213.335938c-82.324219 0-149.332031 66.988281-149.332031 149.332031 0 82.347657 67.007812 149.335938 149.332031 149.335938h213.335938c82.324219 0 149.332031-66.988281 149.332031-149.335938 0-82.34375-67.007812-149.332031-149.332031-149.332031zm-213.335938 234.667969c-47.058593 0-85.332031-38.273438-85.332031-85.335938 0-47.058593 38.273438-85.332031 85.332031-85.332031 47.0625 0 85.335938 38.273438 85.335938 85.332031 0 47.0625-38.273438 85.335938-85.335938 85.335938zm0 0"/></svg>`;

    // css
    const textStyle = `
.switch-set {
    margin-left: 20px;
}
.hide-set {
    transition: opacity 0.3s;
}`;

    // target
    const targets = [
        ["img._6q-tv:not(.hide-set)", null],
        ["img.FFVAD:not(.hide-set)", "eLAPa"],
        ["video:not(.hide-set)", "kPFhm"]
    ];

    // update
    let updating = false;

    css();
    init(10);
    locationChange();
    window.addEventListener("scroll", update);

    function init(times) {
        for (let i = 0; i < times; i++) {
            // switch
            setTimeout(switchButton, 500 * i);
            // hide
            for (const target of targets) {
                setTimeout(() => getTarget(target[0], target[1]), 500 * i);
            }
        }
        // show
        showTarget();
    }

    function switchButton() {
        // check exist
        if (!!document.querySelector(".switch-set")) return;
        // panel
        const panel = document.querySelector(".ctQZg");
        if (!panel) return;
        // switch
        const button = document.createElement("button");
        button.className = "dCJp8 afkep switch-set";
        button.innerHTML = getSwitch() ? iconOn : iconOff;
        button.addEventListener("click", onClick);
        panel.appendChild(button);
    }

    function onClick() {
        const afterClick = !getSwitch();
        GM_setValue("switch", afterClick);
        this.innerHTML = afterClick ? iconOn : iconOff;
        init(3);
    }

    function getTarget(target, root) {
        // check switch.
        if (!getSwitch()) return;
        // hide target.
        document.querySelectorAll(target).forEach(t => {
            t.classList.add("hide-set");
            t.style.opacity = 0.1;
            // the hover is at root.
            if (!!root) {
                if (!t.closest(`div.${root}`)) return;
                const div = t.closest(`div.${root}`).lastElementChild;
                div.addEventListener("mouseenter", addListener);
                div.addEventListener("mouseleave", addListener);
                return;
            }
            // no need to get root.
            t.addEventListener("mouseenter", addListener);
            t.addEventListener("mouseleave", addListener);
        });
    }

    function showTarget() {
        // check switch
        if (getSwitch()) return;
        // show
        for (const target of targets) {
            const tag = target[0].split(":")[0];
            const root = target[1];
            document.querySelectorAll(`${tag}.hide-set`).forEach(t => {
                t.classList.remove("hide-set");
                t.style.opacity = 1;
                // the hover is at root.
                if (!!root) {
                    if (!t.closest(`div.${root}`)) return;
                    const div = t.closest(`div.${root}`).lastElementChild;
                    div.removeEventListener("mouseenter", addListener);
                    div.removeEventListener("mouseleave", addListener);
                    return;
                }
                // no need to get root.
                t.removeEventListener("mouseenter", addListener);
                t.removeEventListener("mouseleave", addListener);
            });
        }
    }

    function getSwitch() {
        return GM_getValue("switch", true);
    }

    function addListener() {
        // the hover is at root.
        if (this.tagName === "DIV") {
            const target = this.parentElement.querySelector("img") || this.parentElement.querySelector("video");
            if (!target) return;
            target.style.opacity = target.style.opacity > 0.5 ? 0.1 : 1;
            return;
        }
        // no need to get root.
        this.style.opacity = this.style.opacity > 0.5 ? 0.1 : 1;
    }

    function css() {
        const style = document.createElement("style");
        style.type = "text/css";
        style.innerHTML = textStyle;
        document.head.appendChild(style);
    }

    function update() {
        if (updating) return;
        updating = true;
        init(3);
        setTimeout(() => { updating = false }, 1000);
    }

    function locationChange() {
        window.addEventListener('locationchange', () => init(3));
        // situation 1
        history.pushState = ( f => function pushState(){
            var ret = f.apply(this, arguments);
            window.dispatchEvent(new Event('pushState'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        })(history.pushState);
        // situation 2
        history.replaceState = ( f => function replaceState(){
            var ret = f.apply(this, arguments);
            window.dispatchEvent(new Event('replaceState'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        })(history.replaceState);
        // situation 3
        window.addEventListener('popstate', () => window.dispatchEvent(new Event('locationchange')));
    }

})();