// ==UserScript== // @name NGA成分指示 // @namespace No namespace. // @version 0.11451 // @license WTFPL // @description 标注出NGA网页版帖子中用户的成分。 // @author You // @match *://bbs.nga.cn/* // @match *://ngabbs.com/* // @match *://nga.178.com/* // @downloadURL https://update.greasyfork.icu/scripts/458017/NGA%E6%88%90%E5%88%86%E6%8C%87%E7%A4%BA.user.js // @updateURL https://update.greasyfork.icu/scripts/458017/NGA%E6%88%90%E5%88%86%E6%8C%87%E7%A4%BA.meta.js // ==/UserScript== (function () { 'use strict'; let forums = {}; let cfs = {}; let cftime = {}; let cfzsPanel; // 查询结果的保质期,默认为3天,单位为秒 const VALIDITY_PERIOD = 3 * 86400; const PANEL_DIV_HTML = ``; class SettingPanel { constructor(form) { this.form = form; this.tagModifier = this.form.querySelector("#tag_modifier"); this.feedback = this.form.querySelector("#cfzs_feedback_info"); // 添加版块按钮 document.getElementById("cfzs_add_forum").addEventListener("click", () => { this.addForum(document.getElementById('cfzs_add_input').value); }); // 添加当前版块按钮 document.getElementById("cfzs_add_current_forum").addEventListener("click", () => { this.addForum(__CURRENT_FID) }); // 清除缓存按钮 document.getElementById("cfzs_close_button").addEventListener("click", () => { this.close() }); // 关闭按钮 document.getElementById("cfzs_clear_cache_button").addEventListener("click", () => { this.clearData() }); // 添加设置按钮 document.getElementsByClassName("right")[0].getElementsByClassName("td")[0].insertAdjacentHTML("afterend", `
成分指示
`); document.getElementById("cfzs_setting_button").addEventListener("click", () => { this.open() }); this.drawPanel(); } drawPanel() { // 绘制面板 this.tagModifier.innerHTML = ""; let placeholder; let thistag; for (let fid in forums) { placeholder = document.createElement("div"); placeholder.insertAdjacentHTML("afterbegin", `
FID:${fid}
`); thistag = placeholder.firstElementChild; this.tagModifier.appendChild(thistag); // 修改备注按钮 thistag.querySelector(`#cfzs_modify_remark_${fid}`).addEventListener("click", () => { this.changeRemark(fid, document.getElementById(`cfzs_remark_${fid}`).value); }); // 删除按钮 thistag.querySelector(`#cfzs_delete_forum_${fid}`).addEventListener("click", () => { this.deleteForum(fid); }); } } open() { // 在打开面板时再更新面板上的信息 this.form.style.display = 'block'; } addForum(fid) { if (fid in forums) { this.feedback.innerHTML = `这个版块已经添加过了…`; return 114514; } let postData; fetch(`https://${window.location.host}/thread.php?fid=${fid}&__output=8`) .then(res => res.arrayBuffer()) .catch(error => { postData = { 'error': [error] } }) .then(buffer => new TextDecoder("gbk").decode(buffer)) .then((res) => { try { postData = JSON.parse(res); } catch { this.feedback.innerHTML = `发生了奇怪的错误,也许此版块(FID:${fid})不存在…`; return 114514; } if (!postData || 'error' in postData) { this.feedback.innerHTML = `发生了奇怪的错误,也许此版块(FID:${fid})不存在…`; return 114514; } let fname = postData.data.__F.name; forums[fid] = fname; window.localStorage.setItem("cfzs_forums", JSON.stringify(forums)); // 添加了一个版块后将cftime清空,以对每个用户发起新的查询 cftime = {}; window.localStorage.setItem('cfzs_cftime', "{}"); this.feedback.innerHTML = `添加了版块${fid}…`; //alert(`${fname}(FID:${fid})添加成功!`); this.drawPanel(); }); } addCurrentForm() { this.addForum(__CURRENT_FID); //forums[__CURRENT_FID] = document.querySelector(`[href='/thread.php?fid=${__CURRENT_FID}'`).innerHTML; } deleteForum(fid) { delete forums[fid]; window.localStorage.setItem("cfzs_forums", JSON.stringify(forums)); this.feedback.innerHTML = `删除了版块${fid}…`; this.drawPanel(); } clearData() { if (window.confirm("这会清空已保存的用户成分,可能会造成成分判断不准确。确定要这样做吗?")) { forums = {}; cfs = {}; cftime = {}; window.localStorage.setItem('cfzs_forums', "{}"); window.localStorage.setItem('cfzs_cfs', "{}"); window.localStorage.setItem('cfzs_cftime', "{}"); alert("清空完毕,刷新以生效…"); } } changeRemark(fid, remark) { forums[fid] = remark; window.localStorage.setItem("cfzs_forums", JSON.stringify(forums)); this.feedback.innerHTML = `将版块${fid}备注为${remark}…`; //this.drawPanel(); } close() { this.form.style.display = 'none'; } } // 初始化脚本 function cfzs_init() { // 生成设置面板 // 从localStorage中读取保存的配置信息 if (!('cfzs_forums' in window.localStorage)) { // 首次使用时添加配置信息 window.localStorage.setItem('cfzs_forums', "{}"); window.localStorage.setItem('cfzs_cfs', "{}"); window.localStorage.setItem('cfzs_cftime', "{}"); } forums = JSON.parse(window.localStorage.getItem('cfzs_forums')); cfs = JSON.parse(window.localStorage.getItem('cfzs_cfs')); cftime = JSON.parse(window.localStorage.getItem('cfzs_cftime')); document.body.insertAdjacentHTML('beforeend', PANEL_DIV_HTML); cfzsPanel = new SettingPanel(document.getElementById('cfzs_setting_panel')); if (Object.keys(forums).length < 1) { alert('您没有关注任何版面。请添加一些以开始使用。'); cfzsPanel.open(); } } // 添加成分 function addChengFen(uid, fid) { // 仅当fid在关注版面中且用户成分尚未包括该fid时才将fid加入用户成分 cftime[uid] = __NOW; window.localStorage.setItem("cfzs_cftime", JSON.stringify(cftime)); if (fid in forums) { cfs[uid].push(fid); cfs[uid] = Array.from(new Set(cfs[uid])); window.localStorage.setItem("cfzs_cfs", JSON.stringify(cfs)); } } // 将查询结果推送到用户面板上 function pushChengFen(form, uid) { let text = '成分: '; let thiscf = []; //console.log(cfs[uid]); for (let i of cfs[uid]) { if (i in forums) thiscf.push(i); } if (thiscf.length > 0) { text += thiscf.map((e) => { return `${forums[e]} (·)` }).join(' / '); } else { text += "群众"; } form.getElementsByClassName("ngatag_container")[0].innerHTML = text; return 114514; } // 主循环 function cfzs_mainLoop() { // 获取每层楼的结构 let floors = Array.from(document.getElementsByClassName("forumbox postbox")); if (floors.length > 0) { floors.forEach(f => { // 筛除分页符 if (!f.querySelector(".postrow")) return 114514; // 判断本楼是否存在已有的查询结果 if (f.getElementsByClassName("ngatag_container").length > 0) { // 若是则直接跳过循环 console.log(`Div existed, jumped...`); return 114514; } else { // 若否,则在用户面板的最下方插入div f.getElementsByClassName("clear")[0].insertAdjacentHTML('beforebegin', '
'); } // 获取本层用户的UID let uid = f.querySelector("a[name='uid']").innerHTML; if (uid in cftime) { // 如果已经保存有该UID的查询结果,则判断查询结果的保存时间 // __NOW 是NGA网页内部的时间戳,希望二哥不要乱动它 if ((__NOW - cftime[uid]) < VALIDITY_PERIOD) { // 若查询结果仍处于保质期内,则直接向div推送查询结果,跳过循环 console.log(`Found available uid, creating div...`); pushChengFen(f, uid); return 114514; } else { // 若查询结果已经过期,则开始一轮新的查询 console.log(`Found out-of-date uid, searching...`); } } else { // 如果遇到新的UID console.log(`Found new uid, searching...`); cfs[uid] = []; } // 查询用户发表的主题 let postData1; fetch(`https://${window.location.host}/thread.php?authorid=${uid}&__output=8`) .then(res => res.arrayBuffer()) .catch(error => { postData1 = { 'error': [error] } }) .then(buffer => new TextDecoder("gbk").decode(buffer)) .then((res) => { postData1 = JSON.parse(res); // 如果用户活跃的版面是关注的版面,则将该版面其加入用户的成分中 for (let i in postData1.data.__T) { addChengFen(uid, postData1.data.__T[i].fid.toString()); } pushChengFen(f, uid); }); // 查询用户发表的回复。逻辑应当与前者是一样的 let postData2; fetch(`https://${window.location.host}/thread.php?searchpost=1&authorid=${uid}&__output=8`) .then(res => res.arrayBuffer()) .catch(error => { postData2 = { 'error': [error] } }) .then(buffer => new TextDecoder("gbk").decode(buffer)) .then((res) => { postData2 = JSON.parse(res); for (let i in postData2.data.__T) { addChengFen(uid, postData2.data.__T[i].fid.toString()); } pushChengFen(f, uid); }); }) } } cfzs_init(); //mainLoop(); setInterval(cfzs_mainLoop, 3000); })();