// ==UserScript==
// @name t66y助手
// @namespace com.t66y.jujufatu
// @author jujufatu
// @version 0.0.6
// @description 优化t66y网页使用体验
// @match http*://*t66y.com/*
// @grant GM_setClipboard
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_registerMenuCommand
// @grant unsafeWindow
// @run-at document-start
// @license CC BY-NC-ND 4.0
// ==/UserScript==
(function() {
"use strict";
var pageWindow = unsafeWindow;
let DOMAIN_ERRORS = GM_getValue("DOMAIN_ERRORS", {});
let BLOCK_DOMAINS = Object.keys(DOMAIN_ERRORS).filter(domain => DOMAIN_ERRORS[domain].count >= 10);
const BLOCK_IMG_LIST = [ "23img.com", "bdimg.com", "sinaimg.cn", "ovkwiz.xyz", "huluxia.com", "imgs.moe", "comicyu.com", "imgtp.com" ].concat(BLOCK_DOMAINS);
const BAD_IMG_SVG = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMjAwcHgiIGhlaWdodD0iMjAwcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICAgICAgICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjMTBiMDE4IiAvPgogICAgICAgICAgPHRleHQgeD0iNTAlIiB5PSI3MS40IiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZjdjNTAwIiBmb250LXNpemU9IjUyIiBmb250LWZhbWlseT0iQXJpYWwiPjx0c3BhbiB4PSI1MCUiIGR5PSIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7ov4fmnJ88L3RzcGFuPjx0c3BhbiB4PSI1MCUiIGR5PSI1Ny4yIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7lm77luoo8L3RzcGFuPjwvdGV4dD48L3N2Zz4=";
const ERROR_FORMAT_BBCODE_TIP_IMG = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMjAwcHgiIGhlaWdodD0iMjAwcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICAgICAgICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJyZWQiIC8+CiAgICAgICAgICA8dGV4dCB4PSI1MCUiIHk9IjYwLjM5OTk5OTk5OTk5OTk5IiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZjdjNTAwIiBmb250LXNpemU9IjM2IiBmb250LWZhbWlseT0iQXJpYWwiPjx0c3BhbiB4PSI1MCUiIGR5PSIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7otLTlm748L3RzcGFuPjx0c3BhbiB4PSI1MCUiIGR5PSIzOS42IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7moLzlvI88L3RzcGFuPjx0c3BhbiB4PSI1MCUiIGR5PSIzOS42IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7plJnor688L3RzcGFuPjwvdGV4dD48L3N2Zz4=";
window.addEventListener("error", function(event) {
if (event.target.tagName === "IMG") {
let imgSrc = event.target.src;
let domain = new URL(imgSrc).hostname;
let now = new Date().getTime();
let domainError = DOMAIN_ERRORS[domain] || {
count: 0,
lastErrorTime: 0
};
if (now - domainError.lastErrorTime > 24 * 60 * 60 * 1e3) {
domainError.count = 1;
} else {
domainError.count++;
}
domainError.lastErrorTime = now;
DOMAIN_ERRORS[domain] = domainError;
if (domainError.count >= 10 && !BLOCK_DOMAINS.includes(domain)) {
BLOCK_DOMAINS.push(domain);
GM_setValue("BLOCK_DOMAINS", BLOCK_DOMAINS);
console.log("添加域名到阻止列表:", domain);
}
GM_setValue("DOMAIN_ERRORS", DOMAIN_ERRORS);
}
}, true);
document.addEventListener("DOMContentLoaded", function() {
replaceImg();
let floors = [ ...document.querySelectorAll(".tpc_content") ];
floors.forEach(floor => {
floor.innerHTML = createMagnetLink(floor.innerHTML);
});
let initComments = [ ...document.querySelectorAll(".post_cont") ];
initComments.forEach(c => {
c.innerHTML = createMagnetLink(c.innerHTML);
});
if (typeof pageWindow.loadComment === "function") {
const originalLoadComment = pageWindow.loadComment;
pageWindow.loadComment = function() {
var data = pageWindow["comm" + arguments[0]];
for (var key in data) {
data[key].c = createMagnetLink(data[key].c);
}
originalLoadComment.apply(this, arguments);
};
}
});
GM_registerMenuCommand("编辑图床黑名单", openBlockedDomainEdit, "e");
function createMagnetLink(str) {
str = decodeURIComponent(str);
str = decodeHtmlEntities(str);
const magnetRegex = /(?<!<[^>]*)(?:magnet:\?xt=urn:btih:)?([A-Z2-7]{32}|[a-fA-F0-9]{40})(?:&dn=([^&\s]+))?(?:&tr=([^&\s]+))?/gi;
function replaceFunc(match, hash, dn, tr) {
const magnetPrefix = "magnet:?xt=urn:btih:";
const decodedDn = dn ? `磁力链接-${decodeURIComponent(dn)}` : `磁力链接-${hash}`;
const trParam = tr ? `&tr=${encodeURIComponent(tr)}` : "";
let href = match.startsWith(magnetPrefix) ? match : `${magnetPrefix}${hash}${dn ? `&dn=${encodeURIComponent(dn)}` : ""}${trParam}`;
href = href.replace(/\s+/g, "");
return `<a href="${href}">${decodedDn}</a> | <a style="cursor: pointer;" onclick="t66ycopy('${href}')">复制</a>`;
}
return str.replace(magnetRegex, replaceFunc);
}
function replaceImg() {
const images = document.getElementsByTagName("img");
for (const img of images) {
if (img.src.startsWith(location.origin)) {
img.src = ERROR_FORMAT_BBCODE_TIP_IMG;
break;
}
if (BLOCK_IMG_LIST.some(domain => img.src.includes(domain))) {
img.src = BAD_IMG_SVG;
}
}
const isBlockedSrc = src => BLOCK_IMG_LIST.some(blockedDomain => src.includes(blockedDomain));
const replaceSrc = node => {
if (node.src.startsWith(location.origin)) {
node.src = ERROR_FORMAT_BBCODE_TIP_IMG;
return;
}
if (node.tagName === "IMG" && isBlockedSrc(node.src)) {
node.src = BAD_IMG_SVG;
}
};
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === "childList") {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
replaceSrc(node);
node.querySelectorAll("img").forEach(replaceSrc);
}
});
} else if (mutation.type === "attributes" && mutation.attributeName === "src") {
replaceSrc(mutation.target);
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: [ "src" ]
});
}
function decodeHtmlEntities(str) {
return str.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/ /g, " ").replace(/¡/g, "¡").replace(/¢/g, "¢").replace(/£/g, "£").replace(/¤/g, "¤").replace(/¥/g, "¥").replace(/¦/g, "¦").replace(/§/g, "§").replace(/¨/g, "¨").replace(/©/g, "©").replace(/ª/g, "ª").replace(/«/g, "«").replace(/¬/g, "¬").replace(/­/g, "").replace(/®/g, "®").replace(/¯/g, "¯").replace(/°/g, "°").replace(/±/g, "±").replace(/²/g, "²").replace(/³/g, "³").replace(/´/g, "´").replace(/µ/g, "µ").replace(/¶/g, "¶").replace(/·/g, "·").replace(/¸/g, "¸").replace(/¹/g, "¹").replace(/º/g, "º").replace(/»/g, "»").replace(/¼/g, "¼").replace(/½/g, "½").replace(/¾/g, "¾").replace(/¿/g, "¿").replace(/&/g, "&");
}
pageWindow.t66ycopy = function(str) {
GM_setClipboard(str);
Message({
msg: "复制成功",
duration: 666
});
};
function openBlockedDomainEdit() {
let container = document.createElement("div");
container.style = "position: fixed; top: 10%; left: 50%; transform: translateX(-50%) scale(0); background-color: white; padding: 20px; border: 1px solid black; border-radius: 10px; z-index: 10000; transition: transform 0.3s ease-in-out;";
container.id = "blockDomainsContainer";
let title = document.createElement("h3");
title.textContent = "编辑黑名单域名";
container.appendChild(title);
let info = document.createElement("p");
info.textContent = "脚本会自动收集加载失败十次以上的图片域名,您可手动增加或删除,一行一个。";
container.appendChild(info);
let textarea = document.createElement("textarea");
textarea.style = "width: 100%; height: 200px;display: block;resize: none;outline: none;border: 2px dashed black;";
textarea.value = BLOCK_DOMAINS.join("\n");
container.appendChild(textarea);
let btnsWrap = document.createElement("div");
btnsWrap.style = "width: 100%;display: flex;justify-content: right;padding: 10px 0;";
container.appendChild(btnsWrap);
let saveButton = document.createElement("button");
saveButton.textContent = "保存";
saveButton.style = "margin-right: 10px; padding: 5px; font-size: 18px;cursor: pointer;";
saveButton.onclick = function() {
BLOCK_DOMAINS = textarea.value.split("\n").filter(Boolean);
GM_setValue("BLOCK_DOMAINS", BLOCK_DOMAINS);
Object.keys(DOMAIN_ERRORS).forEach(domain => {
if (!BLOCK_DOMAINS.includes(domain) && DOMAIN_ERRORS[domain].count >= 10) {
delete DOMAIN_ERRORS[domain];
}
});
GM_setValue("DOMAIN_ERRORS", DOMAIN_ERRORS);
Message({
msg: "域名列表已更新!",
duration: 1024
});
closeUI();
};
btnsWrap.appendChild(saveButton);
let cancelButton = document.createElement("button");
cancelButton.textContent = "取消";
cancelButton.style = "padding: 5px; font-size: 18px;cursor: pointer;";
cancelButton.onclick = closeUI;
btnsWrap.appendChild(cancelButton);
document.body.appendChild(container);
setTimeout(() => container.style.transform = "translateX(-50%) scale(1)", 0);
function closeUI() {
let container = document.getElementById("blockDomainsContainer");
container.style.transform = "translateX(-50%) scale(0)";
setTimeout(() => container.remove(), 300);
}
}
function Message({
msg,
duration = 1024
} = {}) {
const messageElement = document.createElement("div");
messageElement.textContent = msg;
messageElement.style.position = "fixed";
messageElement.style.top = "66px";
messageElement.style.left = "50%";
messageElement.style.transform = "translate(-50%, -50%)";
messageElement.style.backgroundColor = "#10b018";
messageElement.style.color = "#f7c500";
messageElement.style.fontSize = "3rem";
messageElement.style.padding = "20px";
messageElement.style.boxShadow = "0 4px 8px rgba(0,0,0,0.1)";
messageElement.style.borderRadius = "10px";
messageElement.style.zIndex = "1000";
messageElement.style.transition = "opacity 0.5s, transform 0.5s";
messageElement.style.opacity = "0";
document.body.appendChild(messageElement);
setTimeout(() => {
messageElement.style.opacity = "1";
messageElement.style.transform = "translate(-50%, -50%) scale(1)";
}, 10);
setTimeout(() => {
messageElement.style.opacity = "0";
messageElement.style.transform = "translate(-50%, -50%) scale(0.9)";
setTimeout(() => {
document.body.removeChild(messageElement);
}, 500);
}, duration);
}
let style = document.createElement("style");
document.head.appendChild(style);
style.sheet.insertRule(`.bad_bg { background-image: url("${BAD_IMG_SVG}") !important; }`, 0);
})();