// ==UserScript==
// @name Twitter: Hide Image
// @name:zh-TW Twitter 隱藏圖片
// @name:zh-CN Twitter 隐藏图片
// @name:ja Twitter 画像を非表示
// @name:ko Twitter 이미지 숨기기
// @name:ru Twitter Скрыть изображение
// @version 1.0.5
// @description Make Twitter Images Opacity Lower.
// @description:zh-TW 調整 Twitter 圖片的透明度。
// @description:zh-CN 调整 Twitter 图片的透明度。
// @description:ja Twitter 画像の不透明度を低くします。
// @description:ko Twitter 이미지 불투명도를 낮추십시오.
// @description:ru Уменьшите непрозрачность изображений в Twitter.
// @author Hayao-Gai
// @namespace https://github.com/HayaoGai
// @icon https://i.imgur.com/M9oO8K9.png
// @match https://twitter.com/*
// @grant GM_getValue
// @grant GM_setValue
// @downloadURL https://update.greasyfork.icu/scripts/399694/Twitter%3A%20Hide%20Image.user.js
// @updateURL https://update.greasyfork.icu/scripts/399694/Twitter%3A%20Hide%20Image.meta.js
// ==/UserScript==
/* jshint esversion: 6 */
(function() {
'use strict';
// icons made by https://www.flaticon.com/authors/pixel-perfect
const iconOn = ``;
const iconOff = ``;
const textStyle = `
.hide-set {
transition: opacity 0.3s;
opacity: 0.1;
}
.show-set {
opacity: 1 !important;
}
.icon-set {
position: absolute;
transition: opacity 0.3s;
}
.toggle-off-set {
opacity: 0 !important;
}`;
const colors = ["r-13gxpu9", "r-61mi1v", "r-daml9f", "r-xfsgu1", "r-1qkqhnw", "r-nw8l94"];
let currentUrl = document.location.href;
let updating = false;
css();
init(10);
locationChange();
window.addEventListener("scroll", update);
function init(times) {
for (let i = 0; i < times; i++) {
setTimeout(addToggle, 500 * i);
setTimeout(sortToggle, 500 * i);
setTimeout(findImage, 500 * i);
setTimeout(removeBlock, 500 * i);
setTimeout(showImage, 500 * i);
}
}
// toggle
function addToggle() {
// exist
if (!!document.querySelector(".toggle-set")) return;
// check
const panel = document.querySelector(".r-1awozwy.r-1h3ijdo.r-1777fci") || document.querySelector(".r-18u37iz.r-1ye8kvj");
if (!panel) return;
// create
const div1 = document.createElement("div");
div1.className = "css-1dbjc4n r-obd0qt r-1pz39u2 r-1777fci r-1joea0r r-1vsu8ta r-18qmn74 toggle-set";
div1.addEventListener("click", () => onClick(divOn, divOff));
const div2 = document.createElement("div");
div2.className = "css-18t94o4 css-1dbjc4n r-1niwhzg r-42olwf r-sdzlij r-1phboty r-rs99b7 r-1w2pmg r-1vuscfd r-53xb7h r-1ny4l3l r-mk0yit r-o7ynqc r-6416eg r-lrvibr";
const divOn = document.createElement("div");
divOn.className = `css-901oao r-1awozwy r-6koalj r-18u37iz r-16y2uox r-1qd0xha r-a023e6 r-vw2c0b r-1777fci r-eljoum r-dnmrzs r-bcqeeo r-q4m81j r-qvutc0 icon-set ${getColor()}`;
divOn.innerHTML = iconOn;
const svg1 = divOn.querySelector("svg");
svg1.setAttribute("class", `r-4qtqp9 r-yyyyoo r-1q142lx r-dnmrzs r-bnwqim r-1plcrui r-lrvibr ${getColor()}`);
const divOff = document.createElement("div");
divOff.className = `css-901oao r-1awozwy r-6koalj r-18u37iz r-16y2uox r-1qd0xha r-a023e6 r-vw2c0b r-1777fci r-eljoum r-dnmrzs r-bcqeeo r-q4m81j r-qvutc0 icon-set ${getColor()}`;
divOff.innerHTML = iconOff;
const svg2 = divOff.querySelector("svg");
svg2.setAttribute("class", `r-4qtqp9 r-yyyyoo r-1q142lx r-dnmrzs r-bnwqim r-1plcrui r-lrvibr ${getColor()}`);
// on or off
if (getToggle()) divOff.classList.add("toggle-off-set");
else divOn.classList.add("toggle-off-set");
// append
panel.appendChild(div1);
div1.appendChild(div2);
div2.appendChild(divOn);
div2.appendChild(divOff);
}
function sortToggle() {
// sometimes, there's a empty div block the toggle bar.
const panel = document.querySelector(".r-1awozwy.r-1h3ijdo.r-1777fci");
if (!panel) return;
const lastChild = panel.lastElementChild;
if (lastChild.childElementCount === 0) lastChild.remove();
}
function onClick(on, off) {
const afterClick = !getToggle();
GM_setValue("toggle", afterClick);
if (afterClick) {
on.classList.remove("toggle-off-set");
off.classList.add("toggle-off-set");
} else {
on.classList.add("toggle-off-set");
off.classList.remove("toggle-off-set");
}
init(3);
}
function getColor() {
let finalColor = "";
document.querySelectorAll("svg.r-50lct3").forEach(svg => {
if (!!finalColor) return;
const svgClass = svg.className.baseVal;
for (const color of colors) {
if (svgClass.includes(color)) {
finalColor = color;
}
}
});
return finalColor;
}
function getToggle() {
return GM_getValue("toggle", true);
}
// hide
function findImage() {
// toggle
if (!getToggle()) return;
// all images
document.querySelectorAll(".r-4gszlv:not(.check-set)").forEach(function(image) {
image.classList.add("check-set");
// except emoji
if (image.style.backgroundImage.includes("svg")) return;
if (!image.className.includes("hide-set")) image.classList.add("hide-set");
image.classList.remove("show-set");
// event
const touch = image.parentElement.querySelector("img");
touch.addEventListener("mouseenter", imageListener);
touch.addEventListener("mouseleave", imageListener);
});
}
function removeBlock() {
// remove the div block on every avatar.
document.querySelectorAll(".r-1twgtwe").forEach(block => block.remove());
}
function imageListener() {
const image = this.parentElement.querySelector("div");
const isHiding = !image.className.includes("show-set");
if (isHiding) image.classList.add("show-set");
else image.classList.remove("show-set");
}
// show
function showImage() {
// toggle
if (getToggle()) return;
// all images
document.querySelectorAll(".check-set").forEach(function(image) {
image.classList.remove("check-set");
// except emoji
if (image.style.backgroundImage.includes("svg")) return;
image.classList.add("show-set");
// event
const touch = image.parentElement.querySelector("img");
touch.removeEventListener("mouseenter", imageListener);
touch.removeEventListener("mouseleave", imageListener);
});
}
// other
function css() {
const style = document.createElement("style");
style.type = "text/css";
style.innerHTML = textStyle;
document.querySelector("head").appendChild(style);
}
function update() {
if (updating) return;
updating = true;
init(3);
setTimeout(() => { updating = false; }, 1000);
}
function locationChange() {
const observer = new MutationObserver(mutations => {
mutations.forEach(() => {
if (currentUrl !== document.location.href) {
currentUrl = document.location.href;
init(10);
}
});
});
const target = document.querySelector("body");
const config = { childList: true, subtree: true };
observer.observe(target, config);
}
})();