/*
* @Author: MuXia
* @Date: 2023/09/16
*/
// ==UserScript==
// @name 推特获取原图
// @namespace https://github.com/MuXia-0326/twitter-auto-original-picture
// @version 1.0
// @description 推特在新标签页打开图片自动原图
// @author Mossia
// @match https://pbs.twimg.com/*
// @match https://twitter.com/*
// @grant none
// @license MIT
// @downloadURL none
// ==/UserScript==
(function () {
"use strict";
//载入css样式
const css = `/* From www.lingdaima.com */
button {
position: relative;
display: inline-block;
padding: 10px;
text-align: center;
font-size: 18px;
letter-spacing: 1px;
text-decoration: none;
color: rgb(29,155,240);
background: transparent;
cursor: pointer;
transition: ease-out 0.5s;
border-radius: 30px;
border: 2px solid rgb(29,155,240);
border-radius: 10px;
box-shadow: inset 0 0 0 0 rgb(29,155,240);
}
button:hover {
color: white;
box-shadow: inset 0 -100px 0 0 rgb(29,155,240);
}
button:active {
transform: scale(0.9);
}
.Btn {
position: absolute;
top: 2px;
right: 2px;
}
.svgClass {
display: flex;
}
.svgMoveIn {
fill: #fff;
}
.svgMoveOut {
fill: rgb(29,155,240);
}
`;
const styleTag = document.createElement("style");
styleTag.innerText = css;
document.head.append(styleTag);
// 获取当前页面的URL
if (window.location.hostname === "pbs.twimg.com") {
const newUrl = replaceImageSizeName(window.location.href);
if (newUrl !== window.location.href) {
window.location.href = newUrl;
}
} else if (window.location.hostname === "twitter.com") {
addBtn();
}
/**
* @param {string} urlString
*/
function replaceImageSizeName(urlString) {
// 替换name参数的值为"orig"
const url = new URL(urlString);
url.searchParams.set("name", "orig");
return url.toString();
}
function addBtn() {
const processedImages = new Set(); // 用于跟踪已处理的图片
// 创建MutationObserver来监视DOM树的变化
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
// 检查是否有新的图片加载
const tweetContainers = mutation.target.querySelectorAll('div[aria-label][data-testid="tweetPhoto"]');
for (const container of tweetContainers) {
const images = container.querySelectorAll("img");
for (const image of images) {
const imageUrl = image.getAttribute("src");
const classText = image.getAttribute("class") + getRandomIntExclusive(10);
const buttonHtml = `
`;
const parentElement = image.parentElement.parentElement.parentElement.parentElement.parentElement;
if (!processedImages.has(imageUrl)) {
processedImages.add(imageUrl); // 将图片标记为已处理
const newUrl = replaceImageSizeName(imageUrl);
appendBtn(parentElement, newUrl, buttonHtml, classText);
} else {
let btn = parentElement.querySelector(`.Btn`);
if (btn != null) {
return;
}
const newUrl = replaceImageSizeName(imageUrl);
appendBtn(parentElement, newUrl, buttonHtml, classText);
}
}
}
}
});
// 配置MutationObserver以监视子节点添加
const observerConfig = { childList: true, subtree: true };
let reactRoot = document.querySelector("#react-root");
// 在document上启动MutationObserver
observer.observe(reactRoot, observerConfig);
}
function appendBtn(parentElement, newUrl, buttonHtml, classText) {
// 创建按钮元素
const button = document.createElement("div");
button.innerHTML = buttonHtml;
// 按钮点击事件处理程序
button.querySelector(`#copy-${classText}`).addEventListener("click", () => navigator.clipboard.writeText(newUrl));
// 发起fetch请求获取图片内容
button.querySelector(`#download-${classText}`).addEventListener("click", () => {
fetch(newUrl)
.then(function (response) {
if (response.ok) {
return response.blob(); // 以Blob形式解析响应内容
} else {
throw new Error("下载失败");
}
})
.then(function (imageBlob) {
// 创建一个Blob URL,用于保存图片内容
var imageUrl = URL.createObjectURL(imageBlob);
const urlParams = new URL(newUrl);
// 创建一个下载链接
var downloadLink = document.createElement("a");
downloadLink.href = imageUrl;
downloadLink.download =
urlParams.pathname.substring(urlParams.pathname.lastIndexOf("/") + 1) +
"." +
urlParams.searchParams.get("format");
// 模拟用户点击下载链接
downloadLink.click();
// 释放Blob URL以节省内存
URL.revokeObjectURL(imageUrl);
})
.catch(function (error) {
console.error("下载失败:", error);
});
});
// 移入事件处理程序
button.querySelector(`#copy-${classText}`).addEventListener("mouseenter", () => {
const icon = button.querySelector(`#copy-${classText}`).querySelector(".icon");
// 更改按钮颜色
icon.classList.remove("svgMoveOut");
icon.classList.add("svgMoveIn");
});
// 移出事件处理程序
button.querySelector(`#copy-${classText}`).addEventListener("mouseleave", () => {
const icon = button.querySelector(`#copy-${classText}`).querySelector(".icon");
// 更改按钮颜色
icon.classList.remove("svgMoveIn");
icon.classList.add("svgMoveOut");
});
// 移入事件处理程序
button.querySelector(`#download-${classText}`).addEventListener("mouseenter", () => {
const icon = button.querySelector(`#download-${classText}`).querySelector(".icon");
// 更改按钮颜色
icon.classList.remove("svgMoveOut");
icon.classList.add("svgMoveIn");
});
// 移出事件处理程序
button.querySelector(`#download-${classText}`).addEventListener("mouseleave", () => {
const icon = button.querySelector(`#download-${classText}`).querySelector(".icon");
// 更改按钮颜色
icon.classList.remove("svgMoveIn");
icon.classList.add("svgMoveOut");
});
parentElement.appendChild(button);
}
/**
* @param {number} max
*/
function getRandomIntExclusive(max) {
return Math.floor(Math.random() * max);
}
})();