52 Enhance

52 破解论坛增强脚本

  1. // ==UserScript==
  2. // @name 52 Enhance
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.8.1
  5. // @description 52 破解论坛增强脚本
  6. // @author PRO
  7. // @run-at document-start
  8. // @match https://www.52pojie.cn/*
  9. // @icon http://52pojie.cn/favicon.ico
  10. // @license gpl-3.0
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @grant GM_deleteValue
  14. // @grant GM_registerMenuCommand
  15. // @grant GM_unregisterMenuCommand
  16. // @grant GM_addValueChangeListener
  17. // @require https://github.com/PRO-2684/GM_config/releases/download/v1.2.1/config.min.js#md5=525526b8f0b6b8606cedf08c651163c2
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22. const idPrefix = "52-enhance-";
  23. const $ = document.querySelector.bind(document);
  24. const $$ = document.querySelectorAll.bind(document);
  25. const configDesc = {
  26. $default: {
  27. autoClose: false,
  28. folderDisplay: {
  29. parentText: "< 返回",
  30. parentTitle: "返回上级目录",
  31. }
  32. },
  33. hide: {
  34. name: "🫥 隐藏设置",
  35. type: "folder",
  36. items: {
  37. oneClick: { name: "* 一键隐藏", title: "为旧版代码块添加“隐藏代码”的按钮;一键隐藏所有置顶帖;添加隐藏回复的按钮", type: "bool", value: true },
  38. warning: { name: "隐藏提醒", title: "隐藏所有提醒", type: "bool", value: false },
  39. avatarDetail: { name: "隐藏头像详情", title: "隐藏头像下的详情 (统计信息、各类奖章、收听按钮)", type: "bool", value: false },
  40. rating: { name: "隐藏评分", title: "隐藏所有评分", type: "bool", value: false },
  41. comment: { name: "隐藏点评", title: "隐藏所有点评", type: "bool", value: false },
  42. serial: { name: "隐藏序号", title: "隐藏主页帖子列表的序号", type: "bool", value: true },
  43. background: { name: "隐藏背景", title: "隐藏部分背景图片", type: "bool", value: true },
  44. top: { name: "隐藏顶栏", title: "隐藏顶栏和导航栏", type: "bool", value: false },
  45. signature: { name: "隐藏签名档", title: "隐藏所有签名档", type: "bool", value: false },
  46. allowTinySignature: { name: "允许小签名", title: "允许小型签名档 (不含图片)", type: "bool", value: true },
  47. }
  48. },
  49. display: {
  50. name: "🎨 显示设置",
  51. type: "folder",
  52. items: {
  53. regexFilter: { name: "正则过滤", title: "使用正则表达式过滤帖子", type: "str" },
  54. cssFix: { name: "CSS 修复", title: "动态透明度;图标上光标不显示为 pointer", type: "bool", value: true },
  55. imageMaxHeight: { name: "限制图片最大高度", title: "将帖子图片的最大高度限制为 70vh", type: "bool", value: false },
  56. nativeTip: { name: "* 原生提示", title: "使用原生提示框", type: "bool", value: false },
  57. modernize: { name: "现代化", title: "使论坛更现代化", type: "bool", value: false },
  58. }
  59. },
  60. utility: {
  61. name: "🔧 实用功能",
  62. type: "folder",
  63. items: {
  64. getToTop: { name: "* 回到顶部", title: "双击导航栏回到顶部;修改回到顶部按钮行为为原生", type: "bool", value: true },
  65. emojiFix: { name: "* 修复 Emoji", title: "修复 Emoji 显示", type: "bool", value: true },
  66. lazySignatureImage: { name: "* 懒加载签名图片", title: "延迟加载签名档中的图片", type: "bool", value: true },
  67. autoSign: { name: "自动签到", title: "进入论坛时自动后台签到", type: "bool", value: true },
  68. shortcut: { name: "快捷键", title: "Enter: 快速跳到回复栏", type: "bool", value: true },
  69. infiniteScroll: { name: "无限滚动", title: "滚动到末尾时自动加载下一页", type: "bool", value: true },
  70. }
  71. },
  72. };
  73. const config = new GM_config(configDesc);
  74. const configProxy = config.proxy;
  75. // Styles
  76. const styleData = {
  77. forumInactive: "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2048%2048%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20id%3D%22SVGRepo_bgCarrier%22%20stroke-width%3D%220%22%3E%3C%2Fg%3E%3Cg%20id%3D%22SVGRepo_tracerCarrier%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3C%2Fg%3E%3Cg%20id%3D%22SVGRepo_iconCarrier%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M9.24199%2026.4192C9.37704%2026.5551%209.42249%2026.7564%209.35899%2026.9372L9.04753%2027.8242C8.70721%2028.7933%208.32807%2029.6686%207.94869%2030.4389C9.12478%2030.1237%2010.2749%2029.6537%2011.1431%2028.9757L11.8278%2028.441C11.969%2028.3307%2012.1583%2028.3044%2012.3242%2028.372L13.1287%2028.6997C15.149%2029.5228%2017.4898%2030%2020%2030C24.0274%2030%2027.5965%2028.7732%2030.1137%2026.8853C32.6303%2024.9978%2034%2022.5431%2034%2020C34%2017.4569%2032.6303%2015.0022%2030.1137%2013.1147C27.5965%2011.2268%2024.0274%2010%2020%2010C15.9726%2010%2012.4035%2011.2268%209.88629%2013.1147C7.36971%2015.0022%206%2017.4569%206%2020C6%2022.0684%206.89945%2024.0606%208.5795%2025.7522L9.24199%2026.4192ZM6.63696%2032.7576C6.04508%2032.8523%205.51332%2032.91%205.085%2032.9451C4.65926%2032.9801%204.40822%2032.4819%204.65098%2032.1304C4.87529%2031.8056%205.14301%2031.394%205.43023%2030.9028C5.99192%2029.9423%206.62822%2028.6774%207.16049%2027.1616C5.17509%2025.1626%204%2022.6842%204%2020C4%2013.3726%2011.1634%208%2020%208C28.8366%208%2036%2013.3726%2036%2020C36%2026.6274%2028.8366%2032%2020%2032C17.2389%2032%2014.6411%2031.4754%2012.3741%2030.5519C10.6896%2031.8675%208.39738%2032.4761%206.63696%2032.7576Z%22%20fill%3D%22%237d7d7d%22%3E%3C%2Fpath%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M22.2988%2030.8717C21.5494%2030.9563%2020.7817%2031.0001%2020%2031.0001C19.9399%2031.0001%2019.88%2030.9998%2019.8201%2030.9993C21.9473%2034.0883%2026.2448%2036.2001%2031.2%2036.2001C33.4089%2036.2001%2035.4871%2035.7805%2037.3007%2035.0417C38.4838%2035.9656%2040.0417%2036.4537%2041.3574%2036.7115C41.9428%2036.8262%2042.4803%2036.8953%2042.9154%2036.9369C43.3407%2036.9776%2043.5944%2036.4798%2043.3571%2036.1246C43.1384%2035.7973%2042.8807%2035.383%2042.6115%2034.8901C42.2283%2034.1881%2041.8218%2033.3266%2041.4716%2032.3293C43.0599%2030.7302%2044%2028.7475%2044%2026.6001C44%2022.1692%2039.9975%2018.4394%2034.5562%2017.3335C34.792%2018.0278%2034.9377%2018.7481%2034.984%2019.4875C36.5555%2019.908%2037.9398%2020.5785%2039.051%2021.4119C40.9885%2022.865%2042%2024.7198%2042%2026.6001C42%2028.1316%2041.3356%2029.6282%2040.0526%2030.9199L39.3901%2031.587C39.2551%2031.7229%2039.2096%2031.9241%2039.2731%2032.105L39.5846%2032.992C39.7467%2033.4538%2039.9197%2033.8895%2040.0972%2034.2973C39.5092%2034.0802%2038.9679%2033.806%2038.5317%2033.4654L37.847%2032.9307C37.7059%2032.8205%2037.5165%2032.7941%2037.3506%2032.8617L36.5461%2033.1895C34.9792%2033.8278%2033.1579%2034.2001%2031.2%2034.2001C28.0563%2034.2001%2025.2871%2033.2419%2023.349%2031.7883C22.9617%2031.4978%2022.6114%2031.1913%2022.2988%2030.8717Z%22%20fill%3D%22%237d7d7d%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E",
  78. forumActive: "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2048%2048%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20id%3D%22SVGRepo_bgCarrier%22%20stroke-width%3D%220%22%3E%3C%2Fg%3E%3Cg%20id%3D%22SVGRepo_tracerCarrier%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3C%2Fg%3E%3Cg%20id%3D%22SVGRepo_iconCarrier%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M20%2032C28.8366%2032%2036%2026.6274%2036%2020C36%2013.3726%2028.8366%208%2020%208C11.1634%208%204%2013.3726%204%2020C4%2022.6842%205.17509%2025.1626%207.16049%2027.1616C6.35561%2029.4537%205.31284%2031.1723%204.6499%2032.1319C4.4071%2032.4834%204.65714%2032.9802%205.08289%2032.9453C6.78453%2032.8058%2010.1224%2032.3105%2012.3741%2030.5519C14.6411%2031.4754%2017.2389%2032%2020%2032Z%22%20fill%3D%22%237d7d7d%22%3E%3C%2Fpath%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M22.7843%2033.8337C31.4033%2032.7928%2038%2026.9957%2038%2020.0002C38%2019.4632%2037.9611%2018.9333%2037.8855%2018.4121C41.5534%2020.1003%2044%2023.136%2044%2026.6002C44%2028.7476%2043.0599%2030.7303%2041.4716%2032.3295C42.068%2034.0278%2042.8276%2035.3325%2043.3579%2036.1259C43.5953%2036.481%2043.3423%2036.9779%2042.917%2036.9372C41.5041%2036.8021%2039.0109%2036.3773%2037.3007%2035.0418C35.4872%2035.7806%2033.4089%2036.2002%2031.2%2036.2002C27.9781%2036.2002%2025.0343%2035.3074%2022.7843%2033.8337Z%22%20fill%3D%22%237d7d7d%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E",
  79. };
  80. const dynamicStyles = {
  81. "hide.warning": ".vw50_kfc_pb, .vw50_kfc_pt, .vw50_kfc_f { display: none; }",
  82. "hide.avatarDetail": "div.tns.xg2, dl.credit-list, p.md_ctrl, p.xg1, ul.xl.xl2.o.cl { display: none; }",
  83. "hide.rating": "div.pcb > h3.psth.xs1, dl.rate { display: none; }",
  84. "hide.comment": "div.pcb > div.cm { display: none; }",
  85. "hide.serial": "div.boxbg_7ree { background-image: none; padding-left: 0; }",
  86. "hide.background": "body, .psth, .pn { background-image: none; } textarea#fastpostmessage { background: none !important; }",
  87. "hide.top": "#toptb, #nv_ph, #nv, .comiis_nav { display: none; }",
  88. "hide.signature": "div.sign { display: none; }",
  89. "hide.allowTinySignature": "div.sign:not(:has(img)) { display: block; }",
  90. "display.regexFilter": "#threadlisttableid > .regex-filtered { display: none; }",
  91. "display.cssFix": `#jz52top { opacity: 0.2; transition: opacity 0.2s ease-in-out; }
  92. #jz52top:hover { opacity: 0.8; }
  93. .authicn { cursor: initial; }
  94. @media (any-hover: none) {
  95. #jz52top { opacity: 0.8; }
  96. #jz52top:hover { opacity: 0.8; }
  97. }
  98. html { scroll-behavior: smooth; }`,
  99. "display.imageMaxHeight": "#postlist .plc .t_f img, #postlist .plc .tattl img { max-height: 70vh; }",
  100. "display.modernize": `.scbar_icon_td, .scbar_txt_td, .scbar_type_td, .nvhm { background: none; }
  101. .scbar_type_td > a::after { content: " ▼"; }
  102. .scbar_btn_td { background: none; > button#scbar_btn { &::after { content: " 🔍"; } > strong { display: none; }}}
  103. .nvhm { line-height: unset; &::before { content: "🏠"; }}
  104. .fl .bm_h { background-image: none; background-color: #f2f2f2; }
  105. .bm_c > .fl_tb > tbody > tr > td { &.fl_icn > a, &.fl_g > .fl_icn_g > a {
  106. display: block; width: 3em; height: 3em; background-size: contain; > img { display: none; }
  107. &:has(img[src="https://static.52pojie.cn/static/image/common/forum_new.gif"]) { background: url("${styleData.forumActive}"); }
  108. &:has(img[src="https://static.52pojie.cn/static/image/common/forum.gif"]) { background: url("${styleData.forumInactive}"); }
  109. }}
  110. #newspecial, #newspecialtmp, #post_reply, #post_replytmp { padding: 6px 12px; background: #328cdf; border: 1px solid gray; color: white; > img { display: none; } &::after { font-size: 14px; }}
  111. #newspecial::after, #newspecialtmp::after { content: "发帖 📝"; }
  112. #post_reply::after, #post_replytmp::after { content: "回复 🗨️"; }
  113. #p_btn a { background-image: none; background: gray; border-radius: 0.5em; > i { background-image: none; > img { display: none; }
  114. &:has(img[src="https://static.52pojie.cn/static/image/common/fav.gif"]) { &::before { content: "⭐ "; }}
  115. &:has(img[src="https://static.52pojie.cn/static/image/common/agree.gif"]) { &::before { content: "👍 "; }}
  116. &:has(img[src="https://static.52pojie.cn/static/image/common/collection.png"]) { &::before { content: "📚 "; }} /* Alt: 📥 */
  117. &:has(img[src="https://static.52pojie.cn/static/image/common/rec_add.gif"]) { &::before { content: "⬆️ "; }}
  118. &:has(img[src="source/plugin/csu_wechat_scan/image/wx.png"]) { &::before { content: "🟢 "; }} /* TODO: Consider https://simpleicons.org/ */
  119. &:has(img[src="static/image/common/recyclebin.gif"]) { &::before { content: "🗑️ "; }}
  120. }}
  121. .side-star { vertical-align: unset !important; > span[onmouseover^="showMenu"] { > img { display: none; } &::before { content: "⭐"; }}}
  122. .pob.cl > em > a { background-image: none; padding: 5px 10px;
  123. &.cmmnt::before { content: "☕ "; }
  124. &.fastre::before { content: "🗨️ "; }
  125. &.replyadd::before { content: "⬆️ "; }
  126. }
  127. .ico_increase, .ico_fall { background-image: none; text-indent: unset; vertical-align: unset; color: #F26C4F; }
  128. .ico_increase::before { content: "⬆"; }
  129. .ico_fall::before { content: "⬇"; }
  130. .fa_fav, .fa_rss { padding-left: 0; }
  131. .fa_fav { background-image: none; &::before { content: "⭐ "; }}
  132. .fa_rss { background-image: none; &::before { content: "📰 "; }}
  133. #newspecial_menu { width: unset; li { background: none !important; > a { padding: 3px 0; &::before { content: "📄 "; }} &.poll > a::before { content: "📊 "; }}}
  134. #pt .z em { line-height: unset; background: none; font-size: 16px; width: unset; padding: 0 0.5em; }
  135. .authi > .authicn.vm { display: none; }
  136. #threadlisttableid > tbody > tr {
  137. > td.icn {
  138. font-variant-emoji: text; font-size: 1.5em; color: gray;
  139. > a { color: gray; > img { display: none; } &::after { content: "📄︎"; }}
  140. /* &:has(img[src="https://static.52pojie.cn/static/image/common/folder_common.gif"]) { > a::after { color: gray; }} */
  141. &:has(img[src="https://static.52pojie.cn/static/image/common/folder_new.gif"]) { > a::after { color: yellowgreen; }}
  142. &:has(img[src="https://static.52pojie.cn/static/image/common/pin_1.gif"]) { > a::after { content: "📌︎"; }}
  143. &:has(> img[src="https://static.52pojie.cn/static/image/common/ann_icon.gif"]) { &::after { content: "📢︎"; } > img { display: none; }}
  144. }
  145. > th {
  146. > a.closeprev { background-image: none; text-indent: unset; margin: 0; width: 1.5em; height: 1.5em; text-decoration: none; color: gray; &::before { content: "❌︎"; } &:hover { color: #0099cc; }}
  147. /* > img {} */
  148. }
  149. }
  150. .popupcredit { .pc_l, .pc_c, .pc_inner, .pc_r { background: none; } tr { background: #ff7400; display: block; border-radius: 1em; } }
  151. /* img[src="https://static.52pojie.cn/static/image/common/collapsed_no.gif"] */`,
  152. };
  153. // Helper functions
  154. function injectCSS(id, css) {
  155. const style = document.head.appendChild(document.createElement("style"));
  156. style.id = idPrefix + id;
  157. style.textContent = css;
  158. return style;
  159. }
  160. function cssHelper(id, enable) {
  161. const current = document.getElementById(idPrefix + id);
  162. if (current) {
  163. current.disabled = !enable;
  164. } else if (enable) {
  165. injectCSS(id, dynamicStyles[id]);
  166. }
  167. }
  168. function notify(type, text) {
  169. // [Noty](https://ned.im/noty/options)
  170. // `type` (`noty_type__`): alert, love, post, normal, warn, credit, hide
  171. new Noty({
  172. text,
  173. type,
  174. layout: 'topCenter',
  175. theme: 'mint',
  176. closeWith: ['click'],
  177. timeout: 2000,
  178. progressBar: true,
  179. visibilityControl: true,
  180. animation: {
  181. open: 'noty_effects_bottom_open',
  182. close: 'noty_effects_bottom_close'
  183. },
  184. callbacks: {},
  185. }).show();
  186. }
  187. // Regex filter
  188. function regexFilterOne(regex, thread) {
  189. const main = thread.querySelector("tr > th");
  190. if (!main) return;
  191. const category = main.querySelector("em")?.textContent ?? "[未知分类]";
  192. const title = main.querySelector("a.s.xst")?.textContent ?? "未知标题";
  193. const summary = `${category} ${title}`;
  194. thread.classList.toggle("regex-filtered", regex.test(summary));
  195. }
  196. function regexFilter(regexStr) {
  197. const threads = $$("#threadlisttableid > [id^='normalthread_']");
  198. if (regexStr == "") {
  199. threads.forEach(thread => thread.classList.remove("regex-filtered"));
  200. return;
  201. }
  202. const regex = new RegExp(regexStr, "i");
  203. threads.forEach(thread => {
  204. regexFilterOne(regex, thread);
  205. });
  206. }
  207. document.addEventListener("DOMContentLoaded", () => {
  208. const threadsContainer = $("#threadlisttableid");
  209. if (threadsContainer) {
  210. const observer = new MutationObserver(mutations => {
  211. const regex = new RegExp(configProxy["display.regexFilter"], "i");
  212. mutations.forEach(mutation => {
  213. if (mutation.addedNodes.length) {
  214. mutation.addedNodes.forEach(node => {
  215. if (node.id && node.id.startsWith("normalthread_")) {
  216. regexFilterOne(regex, node);
  217. }
  218. });
  219. }
  220. });
  221. });
  222. observer.observe(threadsContainer, { childList: true });
  223. }
  224. });
  225. // Hide
  226. function hideOneClick() {
  227. // Basic CSS
  228. const css = `div.hidden, tr.hidden { display: none; }
  229. td.hidden { cursor: help; background: repeating-linear-gradient(135deg, transparent 0, transparent 6px, #e7e7e7 6px, #e7e7e7 12px, transparent 12px) no-repeat 0 0, #eee; }
  230. td.hidden > div { pointer-events: none; }
  231. td.hidden > div > div > em::after { content: "此回复已被隐藏,点击以重新显示"; }
  232. .plhin:hover td.hidden .hin { opacity: 0.2; }
  233. .toggle-reply-header { opacity: 0.6; }
  234. .toggle-reply-footer { display: block; text-align: center; position: relative; top: 0.8em; }
  235. @media (max-width: 650px) { td.hidden > div > div > em::after { content: ""; } }`;
  236. injectCSS("hide.oneClick", css);
  237. // Hide code
  238. function toggleCode() {
  239. const code = this.parentNode.parentNode.lastChild;
  240. if (code.classList.toggle("hidden")) {
  241. this.textContent = " 显示代码";
  242. } else {
  243. this.textContent = " 隐藏代码";
  244. }
  245. }
  246. $$("em.viewsource").forEach(ele => {
  247. const hide_code = ele.parentNode.appendChild(document.createElement("em"));
  248. hide_code.setAttribute("style", ele.getAttribute("style"));
  249. hide_code.setAttribute("num", ele.getAttribute("num"));
  250. hide_code.textContent = " 隐藏代码";
  251. hide_code.addEventListener("click", toggleCode);
  252. });
  253. // Hide all top threads
  254. const display = Boolean($$("tbody[id^='stickthread_']").length);
  255. const table = document.getElementById("threadlisttableid");
  256. if (display && table) {
  257. function hideAll() {
  258. $$("tbody[id^='stickthread_']").forEach(ele => {
  259. const close = ele.querySelector("a.closeprev");
  260. if (close) close.click();
  261. });
  262. }
  263. const tooltip = $("div#threadlist > div.th > table > tbody > tr > th > div.tf");
  264. const show_top = tooltip.querySelector("span#clearstickthread");
  265. show_top.removeAttribute("style");
  266. show_top.insertAdjacentHTML("beforeend", "&nbsp; ");
  267. const hide_all = show_top.insertAdjacentElement("beforeend", document.createElement("a"));
  268. hide_all.href = "javascript:;";
  269. hide_all.className = "xi2";
  270. hide_all.textContent = "隐藏置顶";
  271. hide_all.title = "隐藏置顶";
  272. hide_all.addEventListener("click", hideAll);
  273. }
  274. // Hide reply
  275. function toggleReply(keep) {
  276. for (const ele of keep.parentElement.children) {
  277. if (ele != keep) {
  278. ele.classList.toggle("hidden");
  279. }
  280. }
  281. const ele = keep.lastElementChild;
  282. if (ele.classList.toggle("hidden")) {
  283. ele.addEventListener("click", e => {
  284. toggleReply(keep);
  285. ele.removeAttribute("title");
  286. }, { once: true });
  287. ele.title = "点击显示被隐藏的回复";
  288. }
  289. }
  290. function toggleReplyFooter() {
  291. toggleReply(this.parentElement.parentElement);
  292. }
  293. function toggleReplyHeader() {
  294. toggleReply(this.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children[3]);
  295. }
  296. $$("table.plhin tbody:has( tr > td.pls)").forEach(ele => {
  297. const toggle_reply_footer = document.createElement("a");
  298. toggle_reply_footer.href = "javascript:void(0);";
  299. toggle_reply_footer.className = "toggle-reply-footer";
  300. toggle_reply_footer.textContent = "🫥";
  301. toggle_reply_footer.addEventListener("click", toggleReplyFooter);
  302. const keep = ele.querySelector("tr:nth-child(4) > td.pls");
  303. keep.appendChild(toggle_reply_footer);
  304. const toggle_reply_header = document.createElement("a");
  305. toggle_reply_header.href = "javascript:void(0);";
  306. toggle_reply_header.className = "toggle-reply-header";
  307. toggle_reply_header.textContent = "👀";
  308. toggle_reply_header.addEventListener("click", toggleReplyHeader);
  309. const header = ele.querySelector("tr:nth-child(1) > td.pls > div.favatar div.authi");
  310. header?.appendChild(toggle_reply_header);
  311. const blocked = ele.querySelector("tr:nth-child(1) > td.plc > div.pct > div.pcb > div.locked");
  312. if (blocked) {
  313. toggle_reply_footer.click(); // Hide blocked replies
  314. }
  315. });
  316. }
  317. // Get to top
  318. function getToTop() {
  319. // Double click navbar to get to top
  320. const nv = document.getElementById("nv");
  321. if (nv) nv.addEventListener("dblclick", e => {
  322. window.scrollTo({ top: 0, behavior: "smooth" });
  323. });
  324. // Change get to top button behavior (use vanilla solution)
  325. const btn = document.getElementById("goTopBtn");
  326. if (btn) btn.onclick = e => {
  327. window.scrollTo({ top: 0, behavior: "smooth" });
  328. };
  329. }
  330. // Emoji fix
  331. function emojiFix() {
  332. const temp = document.createElement("span");
  333. function fixEmoji(html) { // Replace patterns like `&amp;#128077;` with represented emoji
  334. return html.replace(/&(amp;)*#(\d+);/g, (match, p1, p2) => {
  335. temp.innerHTML = `&#${p2};`;
  336. // console.log(`${match} -> ${temp.textContent}`); // DEBUG
  337. return temp.textContent;
  338. });
  339. }
  340. function fix(node) {
  341. // Select text nodes
  342. const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
  343. let textNode;
  344. while (textNode = walker.nextNode()) {
  345. textNode.nodeValue = fixEmoji(textNode.nodeValue);
  346. }
  347. }
  348. const replies = $$("table.plhin td.plc div.pct > div.pcb");
  349. replies.forEach(fix);
  350. const signatures = $$("div.sign, div.bm_c.u_profile > div:nth-child(1) > ul:nth-child(3) > li > table > tbody > tr > td");
  351. signatures.forEach(fix);
  352. }
  353. // Native tip
  354. function nativeTip() {
  355. function format(s) {
  356. // Remove HTML tags
  357. s = s.replace(/(<([^>]+)>)/ig, '');
  358. // Trim spaces at every line and remove empty lines
  359. return s.split("\n").map(e => e.trim()).filter(e => e).join("\n");
  360. }
  361. const links = $$("a[onmouseover='tip.start(this)']");
  362. links.forEach(ele => {
  363. ele.title = format(ele.getAttribute("tips"));
  364. ele.removeAttribute("onmouseover");
  365. ele.tips = null;
  366. });
  367. document.getElementById("mjs:tip")?.remove();
  368. }
  369. // Lazy load signature images
  370. function lazySignatureImage() {
  371. $$("div.sign img").forEach(ele => {
  372. ele.setAttribute("loading", "lazy"); // https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading#images_and_iframes
  373. });
  374. }
  375. // Auto sign
  376. function autoSign(enable) {
  377. if (enable && window === window.top) { // Only run on top frame
  378. const sign1 = $("#um > p:nth-child(3) > a:nth-child(1) > img");
  379. const sign2 = $("#res-sign > a");
  380. const url = sign1?.parentElement?.href;
  381. if (!sign1 || !sign2 || !url || !url.startsWith("https://www.52pojie.cn/home.php?mod=task")) return;
  382. notify("normal", "后台签到中...");
  383. const waf = "https://www.52pojie.cn/waf_text_verify.html";
  384. const iframe = document.body.appendChild(document.createElement("iframe"));
  385. iframe.src = url;
  386. iframe.style.display = "none";
  387. sign1.title = "后台签到中...";
  388. sign1.style.opacity = 0.5;
  389. sign1.height = 20;
  390. sign1.src = "https://static.52pojie.cn/static/image/common/imageloading.gif";
  391. sign1.style.cursor = "progress";
  392. sign1.parentElement.removeAttribute("href");
  393. sign2.textContent = "后台签到中...";
  394. sign2.style.opacity = 0.5;
  395. sign2.style.cursor = "progress";
  396. sign2.removeAttribute("href");
  397. function check() {
  398. const curr = iframe.contentWindow.location.href;
  399. let msg;
  400. if (curr === "https://www.52pojie.cn/home.php?mod=task&item=new" || curr.match(/^https:\/\/www\.52pojie\.cn\/*$/)) {
  401. notify("normal", "签到成功!");
  402. iframe.remove();
  403. msg = "签到成功!";
  404. sign1.src = "https://static.52pojie.cn/static/image/common/wbs.png";
  405. setTimeout(() => {
  406. sign2.remove();
  407. }, 2000);
  408. } else if (curr.startsWith(waf)) {
  409. notify("warn", "触发了防火墙,请稍后刷新页面检查是否签到成功。");
  410. msg = "触发了防火墙,请稍后刷新页面检查是否签到成功。";
  411. sign1.src = "https://static.52pojie.cn/static/image/common/qds.png";
  412. sign1.parentElement.href = url;
  413. } else {
  414. return false;
  415. }
  416. sign1.title = msg;
  417. sign1.style.opacity = 1;
  418. sign1.style.cursor = "default";
  419. sign2.textContent = msg;
  420. sign2.style.opacity = 1;
  421. sign2.style.cursor = "default";
  422. return true;
  423. }
  424. const timer = window.setInterval(() => {
  425. if (check()) window.clearInterval(timer);
  426. }, 500); // Peoredically check if we are done
  427. }
  428. }
  429. // Shortcut
  430. function handleShortcut(e) {
  431. if (e.target.tagName == "TEXTAREA" || e.target.tagName == "INPUT") return;
  432. if (e.key == "Enter") {
  433. const reply = $("textarea#fastpostmessage");
  434. if (reply) {
  435. reply.scrollIntoView();
  436. reply.focus();
  437. e.preventDefault();
  438. }
  439. }
  440. }
  441. function shortcut(enable) {
  442. if (enable) {
  443. document.addEventListener("keydown", handleShortcut);
  444. } else {
  445. document.removeEventListener("keydown", handleShortcut);
  446. }
  447. }
  448. // Infinite scroll
  449. let infiniteScrollEnabled = false;
  450. const infiniteScrollObserver = new IntersectionObserver((entries) => {
  451. if (entries[0].isIntersecting) {
  452. entries[0].target.click();
  453. }
  454. });
  455. function infiniteScroll(enable) {
  456. const next = $("a#autopbn") ?? $("a#darkroommore");
  457. if (!next) return;
  458. if (enable && !infiniteScrollEnabled) {
  459. infiniteScrollObserver.observe(next);
  460. } else if (!enable && infiniteScrollEnabled) {
  461. infiniteScrollObserver.unobserve(next);
  462. }
  463. infiniteScrollEnabled = enable;
  464. }
  465.  
  466. // CSS injection
  467. for (const prop in dynamicStyles) {
  468. cssHelper(prop, configProxy[prop]);
  469. }
  470. // Run on DOMContentLoaded
  471. document.addEventListener("DOMContentLoaded", () => {
  472. configProxy["hide.oneClick"] && hideOneClick();
  473. configProxy["display.nativeTip"] && nativeTip();
  474. configProxy["utility.getToTop"] && getToTop();
  475. configProxy["utility.emojiFix"] && emojiFix();
  476. configProxy["utility.lazySignatureImage"] && lazySignatureImage();
  477. regexFilter(configProxy["display.regexFilter"]);
  478. autoSign(configProxy["utility.autoSign"]);
  479. shortcut(configProxy["utility.shortcut"]);
  480. infiniteScroll(configProxy["utility.infiniteScroll"]);
  481. });
  482. // Listen to config changes
  483. const callbacks = {
  484. "display.regexFilter": regexFilter,
  485. "utility.autoSign": autoSign,
  486. "utility.shortcut": shortcut,
  487. "utility.infiniteScroll": infiniteScroll
  488. };
  489. config.addEventListener("set", e => {
  490. const callback = callbacks[e.detail.prop];
  491. if (callback && (e.detail.before !== e.detail.after)) {
  492. callback(e.detail.after);
  493. }
  494. if (e.detail.prop in dynamicStyles) {
  495. cssHelper(e.detail.prop, e.detail.after);
  496. }
  497. });
  498. })();

QingJ © 2025

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