// ==UserScript== // @name NGA Likes Support // @namespace https://greasyfork.org/users/263018 // @version 1.3.2 // @author snyssss // @description 显示被点赞和粉丝数量,以及发帖数量、IP属地、曾用名 // @match *://bbs.nga.cn/* // @match *://ngabbs.com/* // @match *://nga.178.com/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @noframes // @downloadURL none // ==/UserScript== ((ui) => { if (!ui) return; // KEY const SHOW_OLDNAME_ENABLE_KEY = "SHOW_OLDNAME_ENABLE"; const SHOW_POSTNUM_ENABLE_KEY = "SHOW_POSTNUM_ENABLE"; const SHOW_IPLOC_ENABLE_KEY = "SHOW_IPLOC_ENABLE"; // 显示曾用名 const showOldnameEnable = GM_getValue(SHOW_OLDNAME_ENABLE_KEY) || false; // 显示发帖数 const showPostnumEnable = GM_getValue(SHOW_POSTNUM_ENABLE_KEY) || false; // 显示IP属地 const showIpLocEnable = GM_getValue(SHOW_IPLOC_ENABLE_KEY) || false; // 钩子 const hookFunction = (object, functionName, callback) => { ((originalFunction) => { object[functionName] = function () { const returnValue = originalFunction.apply(this, arguments); callback.apply(this, [returnValue, originalFunction, arguments]); return returnValue; }; })(object[functionName]); }; class UserInfo { execute(task) { task().finally(() => { if (this.waitingQueue.length) { const next = this.waitingQueue.shift(); this.execute(next); } else { this.isRunning = false; } }); } enqueue(task) { if (this.isRunning) { this.waitingQueue.push(task); } else { this.isRunning = true; this.execute(task); } } rearrange() { if (this.data) { const list = Object.values(this.children); for (let i = 0; i < list.length; i++) { if (list[i].source === undefined) { list[i].create(this.data); } Object.entries(this.container).forEach((item) => { list[i].clone(this.data, item); }); } } } reload() { this.enqueue(async () => { this.data = await new Promise((resolve) => { fetch(`/nuke.php?lite=js&__lib=ucp&__act=get&uid=${this.uid}`) .then((res) => res.blob()) .then((blob) => { const reader = new FileReader(); reader.onload = () => { const text = reader.result; const result = JSON.parse( text.replace("window.script_muti_get_var_store=", "") ); resolve(result.data[0]); }; reader.readAsText(blob, "GBK"); }) .catch(() => { resolve(); }); }); if (this.data.usernameChanged && showOldnameEnable) { this.data.oldname = await new Promise((resolve) => { fetch(`/nuke.php?lite=js&__lib=ucp&__act=oldname&uid=${this.uid}`) .then((res) => res.blob()) .then((blob) => { const reader = new FileReader(); reader.onload = () => { const text = reader.result; const result = JSON.parse( text.replace("window.script_muti_get_var_store=", "") ); resolve(result.data[0]); }; reader.readAsText(blob, "GBK"); }) .catch(() => { resolve(); }); }); } Object.values(this.children).forEach((item) => item.destroy()); this.rearrange(); }); } constructor(id) { this.uid = id; this.waitingQueue = []; this.isRunning = false; this.container = {}; this.children = {}; this.reload(); } } class UserInfoWidget { destroy() { if (this.source) { this.source = undefined; } if (this.target) { Object.values(this.target).forEach((item) => { if (item.parentNode) { item.parentNode.removeChild(item); } }); } } clone(data, [argid, container]) { if (this.source) { if (this.target[argid] === undefined) { this.target[argid] = this.source.cloneNode(true); if (this.callback) { this.callback(data, this.target[argid]); } } const isSmall = container.classList.contains("posterInfoLine"); if (isSmall) { const anchor = container.querySelector(".author ~ br"); if (anchor) { anchor.parentNode.insertBefore(this.target[argid], anchor); } } else { container.appendChild(this.target[argid]); } } } constructor(func, callback) { this.create = (data) => { this.destroy(); this.source = func(data); this.target = {}; }; this.callback = callback; } } ui.sn = ui.sn || {}; ui.sn.userInfo = ui.sn.userInfo || {}; ((info) => { const execute = (argid) => { const args = ui.postArg.data[argid]; if (args.comment) return; const uid = +args.pAid; if (uid > 0) { if (info[uid] === undefined) { info[uid] = new UserInfo(uid); } if (document.contains(info[uid].container[argid]) === false) { info[uid].container[argid] = args.uInfoC.closest("tr").querySelector(".posterInfoLine") || args.uInfoC.querySelector("div"); } info[uid].enqueue(async () => { if (info[uid].children[8] === undefined) { info[uid].children[8] = new UserInfoWidget((data) => { const value = Object.values(data.more_info || {}).find( (item) => item.type === 8 )?.data || 0; const element = document.createElement("SPAN"); element.className = "small_colored_text_btn stxt block_txt_c2 vertmod"; element.style.cursor = "default"; element.innerHTML = ` ${value}`; return element; }); } if (info[uid].children[16] === undefined) { info[uid].children[16] = new UserInfoWidget((data) => { const value = data.follow_by_num || 0; const element = document.createElement("SPAN"); element.className = "small_colored_text_btn stxt block_txt_c2 vertmod"; element.style.cursor = "default"; element.innerHTML = ` ${value}`; return element; }); } info[uid].rearrange(); const container = info[uid].container[argid]; const isSmall = container.classList.contains("posterInfoLine"); if (showOldnameEnable) { if (ui._w.__GP.admincheck) { return; } if (isSmall) { const anchor = [ ...container.querySelectorAll("span.usercol"), ].pop().nextElementSibling; const uInfo = info[uid].data; if (anchor && uInfo && uInfo.oldname) { const element = document.createElement("SPAN"); element.className = "usercol nobr"; element.innerHTML = ` · 曾用名 ${Object.values(uInfo.oldname) .map( (item) => `${item.username}` ) .join(", ")}`; anchor.parentNode.insertBefore(element, anchor); } } else { const anchor = container.parentNode.querySelector( '.stat div[class="clear"]' ).parentNode; const uInfo = info[uid].data; if (anchor && uInfo && uInfo.oldname) { const element = document.createElement("DIV"); element.innerHTML = ` 曾用名: ${Object.values(uInfo.oldname) .map( (item) => `${item.username}` ) .join(", ")}`; anchor.parentNode.appendChild(element, anchor); } } } if (showPostnumEnable) { if (ui._w.__GP.admincheck) { return; } if (isSmall) { const anchor = [ ...container.querySelectorAll("span.usercol"), ].pop().nextElementSibling; const uInfo = ui.userInfo.users[uid]; if (anchor && uInfo) { const element = document.createElement("SPAN"); element.className = "usercol nobr"; element.innerHTML = ` · 发帖 ${uInfo.postnum}`; anchor.parentNode.insertBefore(element, anchor); } } else { const anchor = container.parentNode.querySelector( '.stat div[class="clear"]' ); const uInfo = ui.userInfo.users[uid]; if (anchor && uInfo) { const element = document.createElement("DIV"); element.style = "float:left;margin-right:3px;min-width:49%;*width:49%"; element.innerHTML = ` 发帖: ${uInfo.postnum} `; anchor.parentNode.insertBefore(element, anchor); } } } if (showIpLocEnable) { if (ui._w.__GP.admincheck) { return; } if (isSmall) { const anchor = [ ...container.querySelectorAll("span.usercol"), ].pop().nextElementSibling; const uInfo = info[uid].data; if (anchor && uInfo) { const element = document.createElement("SPAN"); element.className = "usercol nobr"; element.innerHTML = ` · 属地 ${uInfo.ipLoc}`; anchor.parentNode.insertBefore(element, anchor); } } else { const anchor = container.parentNode.querySelector( '.stat div[class="clear"]' ); const uInfo = info[uid].data; if (anchor && uInfo) { const element = document.createElement("DIV"); element.style = "float:left;margin-right:3px;min-width:49%;*width:49%"; element.innerHTML = ` 属地: ${uInfo.ipLoc} `; anchor.parentNode.insertBefore(element, anchor); } } } }); } }; const refetch = (arguments) => { const anchor = arguments[0]; const { tid, pid } = arguments[1]; const target = anchor.parentNode.querySelector(".recommendvalue"); if (!target) return; const observer = new MutationObserver(() => { observer.disconnect(); const url = pid ? `/read.php?pid=${pid}` : `/read.php?tid=${tid}`; fetch(url) .then((res) => res.blob()) .then((blob) => { const getLastIndex = (content, position) => { if (position >= 0) { let nextIndex = position + 1; while (nextIndex < content.length) { if (content[nextIndex] === ")") { return nextIndex; } if (content[nextIndex] === "(") { nextIndex = getLastIndex(content, nextIndex); if (nextIndex < 0) { break; } } nextIndex = nextIndex + 1; } } return -1; }; const reader = new FileReader(); reader.onload = async () => { const parser = new DOMParser(); const doc = parser.parseFromString(reader.result, "text/html"); const html = doc.body.innerHTML; const verify = doc.querySelector("#m_posts"); if (verify) { const str = `commonui.postArg.proc(`; const index = html.indexOf(str) + str.length; const lastIndex = getLastIndex(html, index); if (lastIndex >= 0) { const matched = html .substring(index, lastIndex) .match(/'\d+,(\d+),(\d+)'/); if (matched) { const score = (matched[1] |= 0); const score_2 = (matched[2] |= 0); const recommend = score - score_2; target.innerHTML = recommend > 0 ? recommend : 0; } } } }; reader.readAsText(blob, "GBK"); }); }); observer.observe(target, { childList: true, }); }; if (ui.postArg) { Object.keys(ui.postArg.data).forEach((i) => execute(i)); } // 绑定事件 (() => { const initialized = { postDisp: false, postScoreAdd: false, }; const hook = () => { if ( Object.values(initialized).findIndex((item) => item === false) < 0 ) { return; } if (ui.postDisp && initialized.postDisp === false) { hookFunction( ui, "postDisp", (returnValue, originalFunction, arguments) => execute(arguments[0]) ); initialized.postDisp = true; } if (ui.postScoreAdd && initialized.postScoreAdd === false) { hookFunction( ui, "postScoreAdd", (returnValue, originalFunction, arguments) => refetch(arguments) ); initialized.postScoreAdd = true; } }; hookFunction(ui, "eval", hook); hook(); })(); })(ui.sn.userInfo); // 菜单项 (() => { // 显示曾用名 if (showOldnameEnable) { GM_registerMenuCommand("显示曾用名:启用", () => { GM_setValue(SHOW_OLDNAME_ENABLE_KEY, false); location.reload(); }); } else { GM_registerMenuCommand("显示曾用名:禁用", () => { GM_setValue(SHOW_OLDNAME_ENABLE_KEY, true); location.reload(); }); } // 显示发帖数 if (showPostnumEnable) { GM_registerMenuCommand("显示发帖数:启用", () => { GM_setValue(SHOW_POSTNUM_ENABLE_KEY, false); location.reload(); }); } else { GM_registerMenuCommand("显示发帖数:禁用", () => { GM_setValue(SHOW_POSTNUM_ENABLE_KEY, true); location.reload(); }); } // 显示IP属地 if (showIpLocEnable) { GM_registerMenuCommand("显示属地:启用", () => { GM_setValue(SHOW_IPLOC_ENABLE_KEY, false); location.reload(); }); } else { GM_registerMenuCommand("显示属地:禁用", () => { GM_setValue(SHOW_IPLOC_ENABLE_KEY, true); location.reload(); }); } })(); })(commonui);