// ==UserScript==
// @name 52 Enhance
// @namespace http://tampermonkey.net/
// @version 0.4.1
// @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_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @require https://gf.qytechs.cn/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1229665
// ==/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",
};
}
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("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": "dl.credit-list, 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; }",
};
// 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"]) {
// 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", " ");
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
let css = `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 { display: block; text-align: center; position: relative; top: 0.8em; }`;
injectCSS("hide", css);
function toggleReply() {
let keep = this.parentElement.parentElement;
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.apply(this);
ele.removeAttribute("title");
}, { once: true });
ele.title = "点击显示被隐藏的回复";
}
}
document.querySelectorAll("table.plhin tr:nth-child(4) > td.pls").forEach(ele => {
let toggle_reply = document.createElement("a");
toggle_reply.href = "javascript:void(0);";
toggle_reply.className = "toggle-reply";
toggle_reply.textContent = "隐藏/显示回复";
toggle_reply.addEventListener("click", toggleReply);
ele.appendChild(toggle_reply);
});
}
// 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 `&#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 > div.t_fsz");
replies.forEach(fix);
let ratings = document.querySelectorAll("tbody.ratl_l > tr");
ratings.forEach(rating => fix(rating.lastElementChild));
let signatures = document.querySelectorAll("div.sign");
signatures.forEach(fix);
}
// Auto sign
function autoSign(enable) {
if (enable) {
let signEventName = "52-enhance-sign";
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";
if (window.location.href.startsWith("https://www.52pojie.cn/home.php?mod=task")) { // We are on the task page (presumably iframe)
let msg = document.querySelector("div#messagetext > p:nth-child(1)");
if (!msg) return;
window.dispatchEvent(new CustomEvent(signEventName, {
detail: {
msg: msg.textContent,
}
}));
} else if (sign) { // Create an iframe to sign in
let iframe = document.createElement("iframe");
iframe.src = url;
iframe.style.display = "none";
document.body.appendChild(iframe);
iframe.contentWindow.addEventListener(signEventName, e => {
console.debug(e.detail.msg);
if (e.detail.msg.startsWith("抱歉,本期您已申请过此任务,请下期再来") || e.detail.msg.startsWith("恭喜")) { // TODO: msg text?
console.log("Already signed in.");
sign.title = "已签到";
sign.src = "https://static.52pojie.cn/static/image/common/wbs.png";
sign.style.opacity = 1;
sign.style.cursor = "default";
}
});
sign.title = "签到中...";
sign.style.opacity = 0.5;
sign.style.cursor = "progress";
sign.parentElement.removeAttribute("href");
}
}
}
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);
} else {
console.error(`Unexpected config change: ${e.detail}`);
}
}
});
})();