Greasy Fork镜像 支持简体中文。

52 Enhance

52 破解论坛增强脚本

目前為 2024-05-22 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 52 Enhance
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6.7
  5. // @description 52 破解论坛增强脚本
  6. // @author PRO
  7. // @match https://www.52pojie.cn/*
  8. // @icon http://52pojie.cn/favicon.ico
  9. // @license gpl-3.0
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_deleteValue
  13. // @grant GM_registerMenuCommand
  14. // @grant GM_unregisterMenuCommand
  15. // @require https://update.gf.qytechs.cn/scripts/470224/1317473/Tampermonkey%20Config.js
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20. const idPrefix = "52-enhance-";
  21. const $ = document.querySelector.bind(document);
  22. const $$ = document.querySelectorAll.bind(document);
  23. const config_desc = {
  24. "$default": {
  25. value: true,
  26. input: "current",
  27. processor: "not",
  28. formatter: "boolean",
  29. autoClose: false
  30. },
  31. "css-fix": { name: "CSS 修复", title: "动态透明度;图标上光标不显示为 pointer" },
  32. "hide": { name: "* 一键隐藏", title: "为旧版代码块添加“隐藏代码”的按钮;一键隐藏所有置顶帖;添加隐藏回复的按钮" },
  33. "get-to-top": { name: "* 回到顶部", title: "双击导航栏回到顶部;修改回到顶部按钮行为为原生" },
  34. "emoji-fix": { name: "* 修复 Emoji", title: "修复 Emoji 显示" },
  35. "native-tip": { name: "* 原生提示", title: "使用原生提示框", value: false },
  36. "hide-signature": { name: "隐藏签名档", title: "隐藏所有签名档", value: false },
  37. "allow-tiny-signature": { name: "允许小签名", title: "允许小型签名档 (clientHeight <= 41)" },
  38. "hide-warning": { name: "隐藏提醒", title: "隐藏所有提醒", value: false },
  39. "hide-avatar-detail": { name: "隐藏头像详情", title: "隐藏头像下的详情 (统计信息、各类奖章、收听按钮)", value: false },
  40. "hide-rating": { name: "隐藏评分", title: "隐藏所有评分", value: false },
  41. "hide-comment": { name: "隐藏点评", title: "隐藏所有点评", value: false },
  42. "hide-serial": { name: "隐藏序号", title: "隐藏主页帖子列表的序号" },
  43. "hide-background": { name: "隐藏背景", title: "隐藏部分背景图片" },
  44. "image-max-height": { name: "限制图片最大高度", title: "将帖子图片的最大高度限制为 70vh", value: false },
  45. "auto-sign": { name: "自动签到", title: "进入论坛时自动后台签到" },
  46. "shortcut": { name: "快捷键", title: "Enter: 快速跳到回复栏" },
  47. "infinite-scroll": { name: "无限滚动", title: "滚动到末尾时自动加载下一页" }
  48. };
  49. const config = GM_config(config_desc, false);
  50. // Styles
  51. const dynamicStyle = {
  52. "css-fix": `#jz52top { opacity: 0.2; transition: opacity 0.2s ease-in-out; }
  53. #jz52top:hover { opacity: 0.8; }
  54. .authicn { cursor: initial; }
  55. @media (any-hover: none) {
  56. #jz52top { opacity: 0.8; }
  57. #jz52top:hover { opacity: 0.8; }
  58. }
  59. html { scroll-behavior: smooth; }`,
  60. "hide-signature": "div.sign { display: none; }",
  61. "allow-tiny-signature": "div.sign.tiny-sign { display: block; }",
  62. "hide-warning": "div[class^=vw50_kfc_p] { display: none; }",
  63. "hide-avatar-detail": "div.tns.xg2, dl.credit-list, p.md_ctrl, p.xg1, ul.xl.xl2.o.cl { display: none; }",
  64. "hide-rating": "div.pcb > h3.psth.xs1, dl.rate { display: none; }",
  65. "hide-comment": "div.pcb > div.cm { display: none; }",
  66. "hide-serial": "div.boxbg_7ree { background-image: none; padding-left: 0; }",
  67. "hide-background": "body, textarea#fastpostmessage { background: none !important; }",
  68. "image-max-height": "#postlist .plc .t_f img, #postlist .plc .tattl img { max-height: 70vh; }"
  69. };
  70. // Helper function for css
  71. function injectCSS(id, css) {
  72. const style = document.head.appendChild(document.createElement("style"));
  73. style.id = idPrefix + id;
  74. style.textContent = css;
  75. }
  76. function cssHelper(id, enable) {
  77. const current = document.getElementById(idPrefix + id);
  78. if (current) {
  79. current.disabled = !enable;
  80. } else if (enable) {
  81. injectCSS(id, dynamicStyle[id]);
  82. }
  83. }
  84. // Hide
  85. if (config["hide"]) {
  86. // Basic CSS
  87. const css = `div.hidden, tr.hidden { display: none; }
  88. td.hidden { cursor: help; background: repeating-linear-gradient(135deg, transparent 0, transparent 6px, #e7e7e7 6px, #e7e7e7 12px, transparent 12px) no-repeat 0 0, #eee; }
  89. td.hidden > div { pointer-events: none; }
  90. td.hidden > div > div > em::after { content: "此回复已被隐藏,点击以重新显示"; }
  91. .plhin:hover td.hidden .hin { opacity: 0.2; }
  92. .toggle-reply-header { opacity: 0.6; }
  93. .toggle-reply-footer { display: block; text-align: center; position: relative; top: 0.8em; }
  94. @media (max-width: 650px) { td.hidden > div > div > em::after { content: ""; } }`;
  95. injectCSS("hide", css);
  96. // Hide code
  97. function toggleCode() {
  98. const code = this.parentNode.parentNode.lastChild;
  99. if (code.classList.toggle("hidden")) {
  100. this.textContent = " 显示代码";
  101. } else {
  102. this.textContent = " 隐藏代码";
  103. }
  104. }
  105. $$("em.viewsource").forEach(ele => {
  106. const hide_code = ele.parentNode.appendChild(document.createElement("em"));
  107. hide_code.setAttribute("style", ele.getAttribute("style"));
  108. hide_code.setAttribute("num", ele.getAttribute("num"));
  109. hide_code.textContent = " 隐藏代码";
  110. hide_code.addEventListener("click", toggleCode);
  111. });
  112. // Hide all top threads
  113. const display = Boolean($$("tbody[id^='stickthread_']").length);
  114. const table = document.getElementById("threadlisttableid");
  115. if (display && table) {
  116. function hideAll() {
  117. $$("tbody[id^='stickthread_']").forEach(ele => {
  118. const close = ele.querySelector("a.closeprev");
  119. if (close) close.click();
  120. });
  121. }
  122. const tooltip = $("div#threadlist > div.th > table > tbody > tr > th > div.tf");
  123. const show_top = tooltip.querySelector("span#clearstickthread");
  124. show_top.removeAttribute("style");
  125. show_top.insertAdjacentHTML("beforeend", "&nbsp; ");
  126. const hide_all = show_top.insertAdjacentElement("beforeend", document.createElement("a"));
  127. hide_all.href = "javascript:;";
  128. hide_all.className = "xi2";
  129. hide_all.textContent = "隐藏置顶";
  130. hide_all.title = "隐藏置顶";
  131. hide_all.addEventListener("click", hideAll);
  132. }
  133. // Hide reply
  134. function toggleReply(keep) {
  135. for (const ele of keep.parentElement.children) {
  136. if (ele != keep) {
  137. ele.classList.toggle("hidden");
  138. }
  139. }
  140. const ele = keep.lastElementChild;
  141. if (ele.classList.toggle("hidden")) {
  142. ele.addEventListener("click", e => {
  143. toggleReply(keep);
  144. ele.removeAttribute("title");
  145. }, { once: true });
  146. ele.title = "点击显示被隐藏的回复";
  147. }
  148. }
  149. function toggleReplyFooter() {
  150. toggleReply(this.parentElement.parentElement);
  151. }
  152. function toggleReplyHeader() {
  153. toggleReply(this.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children[3]);
  154. }
  155. $$("table.plhin tbody:has( tr > td.pls)").forEach(ele => {
  156. const toggle_reply_footer = document.createElement("a");
  157. toggle_reply_footer.href = "javascript:void(0);";
  158. toggle_reply_footer.className = "toggle-reply-footer";
  159. toggle_reply_footer.textContent = "🫥";
  160. toggle_reply_footer.addEventListener("click", toggleReplyFooter);
  161. const keep = ele.querySelector("tr:nth-child(4) > td.pls");
  162. keep.appendChild(toggle_reply_footer);
  163. const toggle_reply_header = document.createElement("a");
  164. toggle_reply_header.href = "javascript:void(0);";
  165. toggle_reply_header.className = "toggle-reply-header";
  166. toggle_reply_header.textContent = "👀";
  167. toggle_reply_header.addEventListener("click", toggleReplyHeader);
  168. const header = ele.querySelector("tr:nth-child(1) > td.pls > div.favatar div.authi");
  169. header?.appendChild(toggle_reply_header);
  170. const blocked = ele.querySelector("tr:nth-child(1) > td.plc > div.pct > div.pcb > div.locked");
  171. if (blocked) {
  172. toggle_reply_footer.click(); // Hide blocked replies
  173. }
  174. });
  175. }
  176. // Get to top
  177. if (config["get-to-top"]) {
  178. // Double click navbar to get to top
  179. const nv = document.getElementById("nv");
  180. if (nv) nv.addEventListener("dblclick", e => {
  181. window.scrollTo({ top: 0, behavior: "smooth" });
  182. });
  183. // Change get to top button behavior (use vanilla solution)
  184. const btn = document.getElementById("goTopBtn");
  185. if (btn) btn.onclick = e => {
  186. window.scrollTo({ top: 0, behavior: "smooth" });
  187. };
  188. }
  189. // Emoji fix
  190. if (config["emoji-fix"]) {
  191. const temp = document.createElement("span");
  192. function fixEmoji(html) { // Replace patterns like `&amp;#128077;` with represented emoji
  193. return html.replace(/&(amp;)*#(\d+);/g, (match, p1, p2) => {
  194. temp.innerHTML = `&#${p2};`;
  195. // console.log(`${match} -> ${temp.textContent}`); // DEBUG
  196. return temp.textContent;
  197. });
  198. }
  199. function fix(node) {
  200. // Select text nodes
  201. const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
  202. let textNode;
  203. while (textNode = walker.nextNode()) {
  204. textNode.nodeValue = fixEmoji(textNode.nodeValue);
  205. }
  206. }
  207. const replies = $$("table.plhin td.plc div.pct > div.pcb");
  208. replies.forEach(fix);
  209. const signatures = $$("div.sign, div.bm_c.u_profile > div:nth-child(1) > ul:nth-child(3) > li > table > tbody > tr > td");
  210. signatures.forEach(fix);
  211. }
  212. // Native tip
  213. if (config["native-tip"]) {
  214. function format(s) {
  215. // Remove HTML tags
  216. s = s.replace(/(<([^>]+)>)/ig, '');
  217. // Trim spaces at every line and remove empty lines
  218. return s.split("\n").map(e => e.trim()).filter(e => e).join("\n");
  219. }
  220. const links = $$("a[onmouseover='tip.start(this)']");
  221. links.forEach(ele => {
  222. ele.title = format(ele.getAttribute("tips"));
  223. ele.removeAttribute("onmouseover");
  224. ele.tips = null;
  225. });
  226. document.getElementById("mjs:tip")?.remove();
  227. }
  228. // Auto sign
  229. function autoSign(enable) {
  230. if (enable && window === window.top) { // Only run on top frame
  231. const sign1 = $("#um > p:nth-child(3) > a:nth-child(1) > img");
  232. const sign2 = $("#res-sign > a");
  233. const url = sign1?.parentElement?.href;
  234. if (!sign1 || !sign2 || !url) return;
  235. const waf = "https://www.52pojie.cn/waf_text_verify.html";
  236. const iframe = document.body.appendChild(document.createElement("iframe"));
  237. iframe.src = url;
  238. iframe.style.display = "none";
  239. sign1.title = "后台签到中...";
  240. sign1.style.opacity = 0.5;
  241. sign1.height = 20;
  242. sign1.src = "https://static.52pojie.cn/static/image/common/imageloading.gif";
  243. sign1.style.cursor = "progress";
  244. sign1.parentElement.removeAttribute("href");
  245. sign2.textContent = "后台签到中...";
  246. sign2.style.opacity = 0.5;
  247. sign2.style.cursor = "progress";
  248. sign2.removeAttribute("href");
  249. function check() {
  250. const curr = iframe.contentWindow.location.href;
  251. let msg;
  252. if (curr === "https://www.52pojie.cn/home.php?mod=task&item=new" || curr.match(/^https:\/\/www\.52pojie\.cn\/*$/)) {
  253. iframe.remove();
  254. msg = "签到成功!";
  255. sign1.src = "https://static.52pojie.cn/static/image/common/wbs.png";
  256. setTimeout(() => {
  257. sign2.remove();
  258. }, 2000);
  259. } else if (curr.startsWith(waf)) {
  260. msg = "触发了防火墙,请稍后刷新页面检查是否签到成功。";
  261. sign1.src = "https://static.52pojie.cn/static/image/common/qds.png";
  262. sign1.parentElement.href = url;
  263. } else {
  264. return false;
  265. }
  266. sign1.title = msg;
  267. sign1.style.opacity = 1;
  268. sign1.style.cursor = "default";
  269. sign2.textContent = msg;
  270. sign2.style.opacity = 1;
  271. sign2.style.cursor = "default";
  272. return true;
  273. }
  274. const timer = window.setInterval(() => {
  275. if (check()) window.clearInterval(timer);
  276. }, 500); // Peoredically check if we are done
  277. }
  278. }
  279. autoSign(config["auto-sign"]);
  280. // CSS injection
  281. const delayedCSS = ["hide-signature", "allow-tiny-signature"];
  282. for (const prop in dynamicStyle) {
  283. if (delayedCSS.includes(prop)) continue;
  284. cssHelper(prop, config[prop]);
  285. }
  286. // Tag tiny signatures as `tiny-sign`; Delayed CSS injection
  287. document.addEventListener("readystatechange", e => {
  288. if (document.readyState == "complete") {
  289. $$("div.sign").forEach(ele => {
  290. if (ele.clientHeight <= 41) {
  291. ele.classList.add("tiny-sign");
  292. }
  293. });
  294. for (const prop of delayedCSS) {
  295. cssHelper(prop, config[prop]);
  296. }
  297. }
  298. });
  299. // Shortcut
  300. function handleShortcut(e) {
  301. if (e.target.tagName == "TEXTAREA" || e.target.tagName == "INPUT") return;
  302. if (e.key == "Enter") {
  303. const reply = $("textarea#fastpostmessage");
  304. if (reply) {
  305. reply.scrollIntoView();
  306. reply.focus();
  307. e.preventDefault();
  308. }
  309. }
  310. }
  311. function shortcut(enable) {
  312. if (enable) {
  313. document.addEventListener("keydown", handleShortcut);
  314. } else {
  315. document.removeEventListener("keydown", handleShortcut);
  316. }
  317. }
  318. shortcut(config["shortcut"]);
  319. // Infinite scroll
  320. const next = $("a#autopbn");
  321. const observer = new IntersectionObserver((entries, observer) => {
  322. if (entries[0].isIntersecting) {
  323. next?.click();
  324. }
  325. });
  326. function infiniteScroll(enable) {
  327. if (enable && next) {
  328. observer.observe(next);
  329. } else if (!enable && next) {
  330. observer.unobserve(next);
  331. }
  332. }
  333. infiniteScroll(config["infinite-scroll"]);
  334. // Listen to config changes
  335. const callbacks = {
  336. "auto-sign": autoSign,
  337. "shortcut": shortcut,
  338. "infinite-scroll": infiniteScroll
  339. };
  340. window.addEventListener(GM_config_event, e => {
  341. if (e.detail.type == "set") {
  342. const callback = callbacks[e.detail.prop];
  343. if (callback && (e.detail.before !== e.detail.after)) {
  344. callback(e.detail.after);
  345. } else if (e.detail.prop in dynamicStyle) {
  346. cssHelper(e.detail.prop, e.detail.after);
  347. }
  348. }
  349. });
  350. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址