Greasy Fork

Greasy Fork is available in English.

52 Enhance

52 破解论坛增强脚本

当前为 2023-12-10 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         52 Enhance
// @namespace    http://tampermonkey.net/
// @version      0.5.4
// @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      http://greasyfork.icu/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1243832
// ==/UserScript==

(function() {
    'use strict';
    const 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("hide-background", "隐藏背景"); // 隐藏背景图片
    addDesc("auto-sign", "自动签到"); // 自动签到
    addDesc("shortcut", "快捷键"); // 快捷键 (Enter: 快速回复)
    const 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; }
            }
            html { scroll-behavior: smooth; }`,
        "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; }",
        "hide-background": "body { background: none !important; }"
    };
    // 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]);
            }
        }
    });
    // Shortcut
    function handleShortcut(e) {
        if (e.target.tagName == "TEXTAREA" || e.target.tagName == "INPUT") return;
        if (e.key == "Enter") {
            const reply = document.querySelector("textarea#fastpostmessage");
            if (reply) {
                reply.scrollIntoView();
                reply.focus();
                e.preventDefault();
            }
        }
    }
    function shortcut(enable) {
        if (enable) {
            document.addEventListener("keydown", handleShortcut);
        } else {
            document.removeEventListener("keydown", handleShortcut);
        }
    }
    shortcut(config["shortcut"]);
    // Listen to config changes
    let callbacks = {
        "auto-sign": autoSign,
        "shortcut": shortcut
    };
    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);
            }
        }
    });
})();