Sleazy Fork is available in English.

t66y助手

优化t66y网页使用体验

目前为 2023-11-27 提交的版本。查看 最新版本

// ==UserScript==
// @name         t66y助手
// @namespace    com.t66y.jujufatu
// @author       jujufatu
// @version      0.0.3
// @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=";
    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>&nbsp;|&nbsp;<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 (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.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(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&nbsp;/g, " ").replace(/&iexcl;/g, "¡").replace(/&cent;/g, "¢").replace(/&pound;/g, "£").replace(/&curren;/g, "¤").replace(/&yen;/g, "¥").replace(/&brvbar;/g, "¦").replace(/&sect;/g, "§").replace(/&uml;/g, "¨").replace(/&copy;/g, "©").replace(/&ordf;/g, "ª").replace(/&laquo;/g, "«").replace(/&not;/g, "¬").replace(/&shy;/g, "­").replace(/&reg;/g, "®").replace(/&macr;/g, "¯").replace(/&deg;/g, "°").replace(/&plusmn;/g, "±").replace(/&sup2;/g, "²").replace(/&sup3;/g, "³").replace(/&acute;/g, "´").replace(/&micro;/g, "µ").replace(/&para;/g, "¶").replace(/&middot;/g, "·").replace(/&cedil;/g, "¸").replace(/&sup1;/g, "¹").replace(/&ordm;/g, "º").replace(/&raquo;/g, "»").replace(/&frac14;/g, "¼").replace(/&frac12;/g, "½").replace(/&frac34;/g, "¾").replace(/&iquest;/g, "¿").replace(/&amp;/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);
})();