52 Enhance

52 破解论坛增强脚本

目前为 2023-09-19 提交的版本。查看 最新版本

// ==UserScript==
// @name         52 Enhance
// @namespace    http://tampermonkey.net/
// @version      0.5.2
// @description  52 破解论坛增强脚本
// @author       PRO
// @match        https://www.52pojie.cn/*
// @icon         http://52pojie.cn/favicon.ico
// @license      gpl-3.0
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @require      https://greasyfork.org/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1243832
// ==/UserScript==

(function() {
    'use strict';
    let idPrefix = "52-enhance-";
    let config_desc = {};
    function addDesc(id, name, default_value=true) {
        config_desc[id] = {
            name: name,
            value: default_value,
            input: "current",
            processor: "not",
            formatter: "boolean",
            title: name.startsWith("* ") ? `此选项 (${name.slice(2)}) 需要刷新页面才能生效` : `此选项 (${name}) 立即生效`,
            autoClose: false
        };
    }
    addDesc("css-fix", "CSS 修复"); // 动态透明度;图标上光标不显示为 pointer
    addDesc("hide", "* 一键隐藏"); // 为旧版代码块添加“隐藏代码”的按钮;一键隐藏所有置顶帖;添加隐藏回复的按钮
    addDesc("get-to-top", "* 回到顶部"); // 双击导航栏回到顶部;修改回到顶部按钮行为为原生
    addDesc("emoji-fix", "* 修复 Emoji"); // 修复 Emoji 显示
    addDesc("hide-signature", "隐藏签名档", false); // 隐藏所有签名档
    addDesc("allow-tiny-signature", "允许小签名", true); // 允许小型签名档 (clientHeight <= 41)
    addDesc("hide-warning", "隐藏提醒", false); // 隐藏所有提醒
    addDesc("hide-avatar-detail", "隐藏头像详情", false); // 隐藏头像下的详情 (统计信息、各类奖章、收听按钮)
    addDesc("hide-rating", "隐藏评分", false); // 隐藏所有评分
    addDesc("hide-comment", "隐藏点评", false); // 隐藏所有点评
    addDesc("hide-serial", "隐藏序号"); // 隐藏主页帖子列表的序号 (https://www.52pojie.cn/source/plugin/toplist_7ree/template/images/list_bg_7ree.gif)
    addDesc("auto-sign", "自动签到"); // 自动签到
    let config = GM_config(config_desc, false);
    // Styles
    const dynamicStyle = {
        "css-fix": `#jz52top { opacity: 0.2; transition: opacity 0.2s ease-in-out; }
            #jz52top:hover { opacity: 0.8; }
            .authicn { cursor: initial; }
            @media (any-hover: none) {
                #jz52top { opacity: 0.8; }
                #jz52top:hover { opacity: 0.8; }
            }`,
        "hide-signature": "div.sign { display: none; }",
        "allow-tiny-signature": "div.sign.tiny-sign { display: block; }",
        "hide-warning": "div[class^=vw50_kfc_p] { display: none; }",
        "hide-avatar-detail": "div.tns.xg2, dl.credit-list, p.md_ctrl, p.xg1, ul.xl.xl2.o.cl { display: none; }",
        "hide-rating": "div.pcb > h3.psth.xs1, dl.rate { display: none; }",
        "hide-comment": "div.pcb > div.cm { display: none; }",
        "hide-serial": "div.boxbg_7ree { background-image: none; padding-left: 0; }"
    };
    // Helper function for css
    function injectCSS(id, css) {
        let style = document.createElement("style");
        style.id = idPrefix + id;
        style.textContent = css;
        document.head.appendChild(style);
    }
    function cssHelper(id, enable) {
        let current = document.getElementById(idPrefix + id);
        if (current) {
            current.disabled = !enable;
        } else if (enable) {
            injectCSS(id, dynamicStyle[id]);
        }
    }
    // Hide
    if (config["hide"]) {
        // Basic CSS
        let css = `div.hidden, tr.hidden { display: none; }
        td.hidden { cursor: help; background: repeating-linear-gradient(135deg, transparent 0, transparent 6px, #e7e7e7 6px, #e7e7e7 12px, transparent 12px) no-repeat 0 0, #eee; }
        td.hidden > div { pointer-events: none; }
        td.hidden > div > div > em::after { content: "此回复已被隐藏,点击以重新显示"; }
        .plhin:hover td.hidden .hin { opacity: 0.2; }
        .toggle-reply-header { opacity: 0.6; }
        .toggle-reply-footer { display: block; text-align: center; position: relative; top: 0.8em; }`;
        injectCSS("hide", css);
        // Hide code
        function toggleCode() {
            let code = this.parentNode.parentNode.lastChild;
            if (code.classList.toggle("hidden")) {
                this.textContent = " 显示代码";
            } else {
                this.textContent = " 隐藏代码";
            }
        }
        document.querySelectorAll("em.viewsource").forEach(ele => {
            let hide_code = document.createElement("em");
            hide_code.setAttribute("style", ele.getAttribute("style"));
            hide_code.setAttribute("num", ele.getAttribute("num"));
            hide_code.textContent = " 隐藏代码";
            hide_code.addEventListener("click", toggleCode);
            ele.parentNode.appendChild(hide_code);
        });
        // Hide all top threads
        let display = Boolean(document.querySelectorAll("tbody[id^='stickthread_']").length);
        let table = document.getElementById("threadlisttableid");
        if (display && table) {
            function hideAll() {
                document.querySelectorAll("tbody[id^='stickthread_']").forEach(ele => {
                    let close = ele.querySelector("a.closeprev");
                    if (close) close.click();
                });
            }
            let tooltip = document.querySelector("div#threadlist > div.th > table > tbody > tr > th > div.tf");
            let show_top = tooltip.querySelector("span#clearstickthread");
            show_top.removeAttribute("style");
            show_top.insertAdjacentHTML("beforeend", "&nbsp; ");
            let hide_all = document.createElement("a");
            hide_all.href = "javascript:;";
            hide_all.className = "xi2";
            hide_all.textContent = "隐藏置顶";
            hide_all.title = "隐藏置顶";
            hide_all.addEventListener("click", hideAll);
            show_top.insertAdjacentElement("beforeend", hide_all);
        }
        // Hide reply
        function toggleReply(keep) {
            for (let ele of keep.parentElement.children) {
                if (ele != keep) {
                    ele.classList.toggle("hidden");
                }
            }
            let ele = keep.lastElementChild;
            if (ele.classList.toggle("hidden")) {
                ele.addEventListener("click", e => {
                    toggleReply(keep);
                    ele.removeAttribute("title");
                }, { once: true });
                ele.title = "点击显示被隐藏的回复";
            }
        }
        function toggleReplyFooter() {
            toggleReply(this.parentElement.parentElement);
        }
        function toggleReplyHeader() {
            toggleReply(this.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children[3]);
        }
        document.querySelectorAll("table.plhin tbody:has( tr > td.pls)").forEach(ele => {
            let toggle_reply_footer = document.createElement("a");
            toggle_reply_footer.href = "javascript:void(0);";
            toggle_reply_footer.className = "toggle-reply-footer";
            toggle_reply_footer.textContent = "隐藏/显示回复";
            toggle_reply_footer.addEventListener("click", toggleReplyFooter);
            let keep = ele.querySelector("tr:nth-child(4) > td.pls");
            keep.appendChild(toggle_reply_footer);
            let toggle_reply_header = document.createElement("a");
            toggle_reply_header.href = "javascript:void(0);";
            toggle_reply_header.className = "toggle-reply-header";
            toggle_reply_header.textContent = "👀";
            toggle_reply_header.addEventListener("click", toggleReplyHeader);
            let header = ele.querySelector("tr:nth-child(1) > td.pls > div.favatar div.authi");
            header.appendChild(toggle_reply_header);
            if (!keep.parentElement.parentElement.firstElementChild.querySelector("div.avatar img")) {
                toggle_reply_footer.click(); // Hide reply by default if no avatar (blocked user)
            }
        });
    }
    // Get to top
    if (config["get-to-top"]) {
        // Double click navbar to get to top
        let nv = document.getElementById("nv");
        if (nv) nv.addEventListener("dblclick", e => {
            window.scrollTo({ top: 0, behavior: "smooth" });
        });
        // Change get to top button behavior (use vanilla solution)
        let btn = document.getElementById("goTopBtn");
        if (btn) btn.onclick = e => {
            window.scrollTo({ top: 0, behavior: "smooth" });
        };
    }
    // Emoji fix
    if (config["emoji-fix"]) {
        let temp = document.createElement("span");
        function fixEmoji(html) { // Replace patterns like `&amp;#128077;` with represented emoji
            return html.replace(/&(amp;)*#(\d+);/g, (match, p1, p2) => {
                temp.innerHTML = `&#${p2};`;
                // console.log(`${match} -> ${temp.textContent}`); // DEBUG
                return temp.textContent;
            });
        }
        function fix(node) {
            // Select text nodes
            let walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
            let textNode;
            while (textNode = walker.nextNode()) {
                textNode.nodeValue = fixEmoji(textNode.nodeValue);
            }
        }
        let replies = document.querySelectorAll("table.plhin td.plc div.pct > div.pcb");
        replies.forEach(fix);
        let signatures = document.querySelectorAll("div.sign, div.bm_c.u_profile > div:nth-child(1) > ul:nth-child(3) > li > table > tbody > tr > td");
        signatures.forEach(fix);
    }
    // Auto sign
    function autoSign(enable) {
        if (enable && window === window.top) { // Only run on top frame
            let sign = document.querySelector("#um > p:nth-child(3) > a:nth-child(1) > img");
            let url = "https://www.52pojie.cn/home.php?mod=task&do=apply&id=2&referer=%2F";
            let waf = "https://www.52pojie.cn/waf_text_verify.html";
            if (sign) { // Checkin
                let iframe = document.createElement("iframe");
                iframe.src = url;
                iframe.style.display = "none";
                document.body.appendChild(iframe);
                sign.title = "后台签到中...";
                sign.style.opacity = 0.5;
                sign.height = 20;
                sign.src = "https://static.52pojie.cn/static/image/common/imageloading.gif";
                sign.style.cursor = "progress";
                sign.parentElement.removeAttribute("href");
                function check() {
                    let curr = iframe.contentWindow.location.href;
                    let msg;
                    if (curr === "https://www.52pojie.cn/home.php?mod=task&item=new" || curr.match(/https:\/\/www\.52pojie\.cn\/*/)) {
                        msg = "签到成功!";
                        sign.src = "https://static.52pojie.cn/static/image/common/wbs.png";
                    } else if (curr.startsWith(waf)) {
                        msg = "触发了防火墙,请稍后刷新页面检查是否签到成功。";
                        sign.src = "https://static.52pojie.cn/static/image/common/qds.png";
                        sign.parentElement.href = url;
                    } else {
                        return false;
                    }
                    sign.title = msg;
                    sign.style.opacity = 1;
                    sign.style.cursor = "default";
                    return true;
                }
                let id = window.setInterval(() => {
                    if (check()) window.clearInterval(id);
                }, 500); // Peoredically check if we are done
            }
        }
    }
    autoSign(config["auto-sign"]);
    // CSS injection
    let delayedCSS = ["hide-signature", "allow-tiny-signature"];
    for (let prop in dynamicStyle) {
        if (delayedCSS.includes(prop)) continue;
        cssHelper(prop, config[prop]);
    }
    // Tag tiny signatures as `tiny-sign`; Delayed CSS injection
    document.addEventListener("readystatechange", e => {
        if (document.readyState == "complete") {
            document.querySelectorAll("div.sign").forEach(ele => {
                if (ele.clientHeight <= 41) {
                    ele.classList.add("tiny-sign");
                }
            });
            for (let prop of delayedCSS) {
                cssHelper(prop, config[prop]);
            }
        }
    });
    // Listen to config changes
    let callbacks = {
        "auto-sign": autoSign
    };
    window.addEventListener(GM_config_event, e => {
        if (e.detail.type == "set") {
            let callback = callbacks[e.detail.prop];
            if (callback && (e.detail.before !== e.detail.after)) {
                callback(e.detail.after);
            } else if (e.detail.prop in dynamicStyle) {
                cssHelper(e.detail.prop, e.detail.after);
            }
        }
    });
})();