NodeSeek X

【原NodeSeek增强】自动签到、自动滚动翻页

目前为 2024-03-11 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name NodeSeek X
  3. // @namespace http://www.nodeseek.com/
  4. // @version 0.3-beta.2
  5. // @description 【原NodeSeek增强】自动签到、自动滚动翻页
  6. // @author dabao
  7. // @match *://www.nodeseek.com/*
  8. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACz0lEQVR4Ae3B32tVdQAA8M85u7aVHObmzJVD0+ssiphstLEM62CBlCBEIAYhUoGGD/kiRUo+9CIEElFZgZJFSApBVhCUX2WFrVQKf5Qy26SgdK4pN7eZu+cbtyfJ/gLx83HD9SAhlEyXupiPhUSTeonRfNw1ws2aRJeN5jHcolFhJJ9M8Zj99piDTnv12SjzfzIb9dmrC7Pttt8ykjDVLsu8ZZ1GH1oqeDofJLtJh4fMEw3Y72jlCuEO2+W+sNJFr3vOZ1YIi8NIGA29hDWhGgZDJ2Rt2ZvZSBazmMUsZsPZ1qwVQmcYDNWwhtAbRsNIWJx6WLPDfgxNVkm9nR8hm+XduLba7F9RtcXztmUzyY/YJrUqNPvBYc0eSS3CwXxMl4WG7CarsyEuvU2HOkRNujSw3PosxR6DFurKxx3E/akFohPo0aDfEO61os5LdrtLVWG1TzxokifdiSH9GnTjuGhBqsWE39GOo3kVi8wsmeVW00SJ200zA9r0kFcdQzv+MKElVW/S+L5EE86pmUth3BV/SzCOCUjMVXMWzfsSYybVl1SlSlESkagpuOI1nzshFX1gyAF1UKhJEKOkJFVNXVBv+pJoBK1qBkh86z1/SaR+9o5zEgoDaloxsiSart6F1Bkl83ESHWEKvvEbqZJETaokgSH9hCk6cBLtSs6kDqEb/cZ0K+MnO0X/VdhRGUBZjzH9uA+HUl+a0BvmO+J7bVZSKWz1kehqhfe9oWalNoccDmW9JnyV+toxsy3PK3aY9Gx4gMp567ziV4WawpCXra+MEhZ5xqTtecVycxzXlxA22OK4ZYbt9LjvrM5PkNUp6zVPdNpBv1QKwt126Paxp8zwqXu8kG8pYZdHlT2Rvxo2aVG2ObyYn65UnXLKVULZZrP02ZRfCms1OmAXCSHRYqrLzuZFaDFV6s/8omuERs0Kl/LzITVTvTHDeXTD9eAftAsSYhXYOWUAAAAASUVORK5CYII=
  9. // @require https://cdn.staticfile.org/notie/4.3.1/notie.min.js
  10. // @resource notieStyle https://cdn.staticfile.org/notie/4.3.1/notie.min.css
  11. // @resource highlightStyle https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_deleteValue
  16. // @grant GM_notification
  17. // @grant GM_registerMenuCommand
  18. // @grant GM_unregisterMenuCommand
  19. // @grant GM_getResourceText
  20. // @grant GM_addElement
  21. // @grant GM_addStyle
  22. // @grant GM_openInTab
  23. // @grant unsafeWindow
  24. // @run-at document-end
  25. // @license GPL-3.0 License
  26. // @supportURL https://www.nodeseek.com/post-36263-1
  27. // @homepageURL https://www.nodeseek.com/post-36263-1
  28. // ==/UserScript==
  29.  
  30. (function () {
  31. 'use strict';
  32.  
  33. const scriptInfo = GM_info.script;
  34. const version = scriptInfo.version;
  35. const author = scriptInfo.author;
  36. const name = scriptInfo.name;
  37. const icon = scriptInfo.icon;
  38.  
  39. const util = {
  40. clog(c) {
  41. console.group(`%c %c [${name}]-v${version} by ${author}`, `background:url(${icon}) center center no-repeat;background-size:12px;padding:3px`, "");
  42. console.log(c);
  43. console.groupEnd();
  44. },
  45. getValue(name) {
  46. return GM_getValue(name);
  47. },
  48. setValue(name, value) {
  49. GM_setValue(name, value);
  50. },
  51. sleep(time) {
  52. return new Promise((resolve) => setTimeout(resolve, time));
  53. },
  54. addStyle(id, tag, css) {
  55. tag = tag || 'style';
  56. let doc = document, styleDom = doc.getElementById(id);
  57. if (styleDom) return;
  58. let style = doc.createElement(tag);
  59. style.rel = 'stylesheet';
  60. style.id = id;
  61. tag === 'style' ? style.innerHTML = css : style.href = css;
  62. document.head.appendChild(style);
  63. },
  64. getAttributesByPrefix(element, prefix) {
  65. var attributes = element.attributes;
  66. var matchingAttributes = {};
  67. for (var attribute of attributes) {
  68. var attributeName = attribute.name;
  69. var attributeValue = attribute.value;
  70.  
  71. if (attributeName.startsWith(prefix)) {
  72. matchingAttributes[attributeName] = attributeValue;
  73. }
  74. }
  75. return matchingAttributes;
  76. },
  77. data(element, key, value) {
  78. if (arguments.length < 2) {
  79. return undefined;
  80. }
  81. if (value != undefined) {
  82. element.dataset[key] = value;
  83. }
  84. return element.dataset[key];
  85. },
  86. post(url, data, headers, type) {
  87. if (typeof data === 'object') {
  88. data = JSON.stringify(data);
  89. }
  90. return new Promise((resolve, reject) => {
  91. GM_xmlhttpRequest({
  92. method: "POST", url, headers, data,
  93. responseType: type || 'json',
  94. onload: (res) => resolve(res.response || res.responseText),
  95. onerror: (err) => reject(err)
  96. });
  97. });
  98. },
  99. get(url, headers, type) {
  100. return new Promise((resolve, reject) => {
  101. let requestObj = GM_xmlhttpRequest({
  102. method: "GET", url, headers,
  103. responseType: type || 'json',
  104. onload: (res) => {
  105. if (res.status === 204) {
  106. requestObj.abort();
  107. }
  108. resolve(res.response || res.responseText);
  109. },
  110. onerror: (err) => reject(err)
  111. });
  112. });
  113. },
  114. openLinkInNewTab(selector) {
  115. var allLinks = document.querySelectorAll(selector);
  116.  
  117. allLinks.forEach(function (link) {
  118. link.setAttribute('target', '_blank');
  119. });
  120. },
  121. getCurrentDate(){
  122. let localTimezoneOffset = (new Date()).getTimezoneOffset();
  123. let beijingOffset = 8 * 60;
  124. let beijingTime = new Date(Date.now() + (localTimezoneOffset + beijingOffset) * 60 * 1000);
  125. let timeNow = `${beijingTime.getFullYear()}/${(beijingTime.getMonth() + 1)}/${beijingTime.getDate()}`;
  126. return timeNow;
  127. }
  128. };
  129.  
  130. const opts = {
  131. post: {
  132. pathPattern: /^\/(categories\/|page|award|search|$)/,
  133. scrollThreshold: 200,
  134. nextPagerSelector: '.nsk-pager a.pager-next',
  135. postListSelector: 'ul.post-list',
  136. topPagerSelector: 'div.nsk-pager.pager-top',
  137. bottomPagerSelector: 'div.nsk-pager.pager-bottom',
  138. },
  139. comment: {
  140. pathPattern: /^\/post-/,
  141. scrollThreshold: 690,
  142. nextPagerSelector: '.nsk-pager a.pager-next',
  143. postListSelector: 'ul.comments',
  144. topPagerSelector: 'div.nsk-pager.post-top-pager',
  145. bottomPagerSelector: 'div.nsk-pager.post-bottom-pager',
  146. },
  147. setting: {
  148. SETTING_SIGN_IN_STATUS: 'setting_sign_in_status',
  149. SETTING_SIGN_IN_LAST_DATE: 'setting_sign_in_last_date',
  150. SETTING_SIGN_IN_IGNORE_DATE: 'setting_sign_in_ignore_date'
  151. }
  152. };
  153.  
  154. let main = {
  155. // 初始化配置数据
  156. initValue() {
  157. let value = [
  158. { name: opts.setting.SETTING_SIGN_IN_STATUS, defaultValue: 0 },
  159. { name: opts.setting.SETTING_SIGN_IN_LAST_DATE, defaultValue: '1753/1/1' },
  160. { name: opts.setting.SETTING_SIGN_IN_IGNORE_DATE, defaultValue: '1753/1/1' }
  161. ];
  162. this.upgradeConfig();
  163. value.forEach((v) => util.getValue(v.name) === undefined && util.setValue(v.name, v.defaultValue));
  164. },
  165. // 升级配置项
  166. upgradeConfig(){
  167. const upgradeConfItem=(oldConfKey,newConfKey)=>{
  168. if(util.getValue(oldConfKey)&&util.getValue(newConfKey)===undefined){
  169. util.clog(`升级配置项 ${oldConfKey} ${newConfKey}`);
  170. util.setValue(newConfKey,util.getValue(oldConfKey));
  171. GM_deleteValue(oldConfKey);
  172. }
  173. };
  174. upgradeConfItem('menu_signInTime',opts.setting.SETTING_SIGN_IN_LAST_DATE);
  175. },
  176. loginStatus: false,
  177. //检查是否登陆
  178. checkLogin() {
  179. if (unsafeWindow.meCard && unsafeWindow.meCard.logined) {
  180. this.loginStatus = true;
  181. util.clog(`当前登录用户 ${unsafeWindow.meCard.user.member_name} (ID ${unsafeWindow.meCard.user.member_id})`);
  182. }
  183. },
  184. // 自动签到
  185. autoSignIn(rand) {
  186. if (!this.loginStatus) return
  187. if(util.getValue(opts.setting.SETTING_SIGN_IN_STATUS)===0) return;
  188.  
  189. let timeNow = util.getCurrentDate(),
  190. timeOld = util.getValue(opts.setting.SETTING_SIGN_IN_LAST_DATE);
  191. if (!timeOld || timeOld != timeNow) { // 是新的一天
  192. util.setValue(opts.setting.SETTING_SIGN_IN_LAST_DATE, timeNow); // 写入签到时间以供后续比较
  193. this.signInRequest(rand);
  194. }
  195. },
  196. addSignTips() {
  197. if (!this.loginStatus) return
  198. if(util.getValue(opts.setting.SETTING_SIGN_IN_STATUS)!==0) return;
  199.  
  200. const timeNow = util.getCurrentDate();
  201. const { SETTING_SIGN_IN_IGNORE_DATE, SETTING_SIGN_IN_LAST_DATE } = opts.setting;
  202. const timeIgnore = util.getValue(SETTING_SIGN_IN_IGNORE_DATE);
  203. const timeOld = util.getValue(SETTING_SIGN_IN_LAST_DATE);
  204.  
  205. if (timeNow === timeIgnore || timeNow === timeOld) return;
  206.  
  207. const _this = this;
  208. let tip = document.createElement('div');
  209. tip.className = "nsplus-tip";
  210. let tip_p = document.createElement('p');
  211. tip_p.innerHTML = '今天你还没有签到哦!&emsp;【<a class="sign_in_btn" data-rand="true" href="javascript:;">随机抽个鸡腿</a>】&emsp;【<a class="sign_in_btn" data-rand="false" href="javascript:;">只要5个鸡腿</a>】&emsp;【<a id="sign_in_ignore" href="javascript:;">今天不再提示</a>】';
  212. tip.appendChild(tip_p);
  213. tip.querySelectorAll('.sign_in_btn').forEach(function (item) {
  214. item.addEventListener("click", function (e) {
  215. const rand = util.data(this, 'rand');
  216. _this.signInRequest(rand);
  217. tip.remove();
  218. util.setValue(opts.setting.SETTING_SIGN_IN_LAST_DATE, timeNow); // 写入签到时间以供后续比较
  219. })
  220. });
  221. tip.querySelector('#sign_in_ignore').addEventListener("click", function (e) {
  222. tip.remove();
  223. util.setValue(opts.setting.SETTING_SIGN_IN_IGNORE_DATE,timeNow);
  224. });
  225.  
  226. document.querySelector('#nsk-frame').before(tip);
  227. },
  228. signInRequest(rand) {
  229. util.post('/api/attendance?random=' + (rand || true), {}, { "Content-Type": "application/json" }, '').then(function (json) {
  230. if (json.success) {
  231. GM_notification({ text: '签到成功!今天午饭+' + json.gain + '个鸡腿; 积攒了' + json.current + '个鸡腿了', timeout: 3500 });
  232. }
  233. else {
  234. GM_notification({ text: json.message, timeout: 3500 });
  235. }
  236. }).catch(function (err) {
  237. util.clog(err)
  238. });
  239. util.clog(`[${name}] 签到完成`);
  240. },
  241. is_show_quick_comment: false,
  242. quickComment() {
  243. if (!this.loginStatus) return
  244.  
  245. if (!opts.comment.pathPattern.test(location.pathname)) return;
  246. const _this = this;
  247. const commentDiv = document.querySelector('#fast-nav-button-group #back-to-parent').cloneNode(true);
  248. commentDiv.id = 'back-to-comment';
  249. commentDiv.innerHTML = '<svg class="iconpark-icon" style="width: 24px; height: 24px;"><use href="#comments"></use></svg>';
  250. commentDiv.addEventListener("click", function () {
  251. if (_this.is_show_quick_comment) {
  252. return;
  253. }
  254. const clientHeight = document.documentElement.clientHeight, clientWidth = document.documentElement.clientWidth;
  255. const md = document.querySelector('.md-editor');
  256. const mdHeight = md.clientHeight, mdWidth = md.clientWidth;
  257. const top = (clientHeight / 2) - (mdHeight / 2), left = (clientWidth / 2) - (mdWidth / 2);
  258. md.style.position = 'fixed'; md.style.top = `${top}px`; md.style.left = `${left}px`; md.style.width = '100%'; md.style.maxWidth = '720px'; md.style.zIndex = '999'; _this.addEditorCloseButton();
  259.  
  260. _this.is_show_quick_comment = true;
  261. });
  262. document.querySelector('#back-to-parent').before(commentDiv);
  263. //document.querySelectorAll('div.comment-menu > div:nth-child(4) ').forEach(function (item) { item.onclick = function (e) { var md = document.querySelector('.md-editor'); md.style.position = 'fixed'; md.style.bottom = 0; md.style.width = '100%'; md.style.maxWidth = '720px'; md.style.zIndex = '999'; _this.addEditorCloseButton() } })
  264. },
  265. addEditorCloseButton() {
  266. const _this = this;
  267. const fullScreenToolbar = document.querySelector('#editor-body .window_header > :last-child');
  268. const cloneToolbar = fullScreenToolbar.cloneNode(true);
  269. cloneToolbar.setAttribute('title', '关闭');
  270. cloneToolbar.querySelector('span').classList.replace('i-icon-full-screen-one', 'i-icon-close');
  271. cloneToolbar.querySelector('span').innerHTML = '<svg width="16" height="16" viewBox="0 0 48 48" fill="none"><path d="M8 8L40 40" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8 40L40 8" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
  272. cloneToolbar.addEventListener("click", function (e) {
  273. document.querySelector('.md-editor').style = "";
  274. this.remove();
  275. _this.is_show_quick_comment = false;
  276. });
  277. fullScreenToolbar.after(cloneToolbar);
  278. },
  279. //新窗口打开帖子
  280. openPostInNewTab() {
  281. util.openLinkInNewTab('.post-title>a[href]');
  282. },
  283. //自动点击跳转页链接
  284. autoJump() {
  285. if (!/^\/jump/.test(location.pathname)) return;
  286. document.querySelector('.btn').click();
  287. },
  288. blockPost(ele) {
  289. ele = ele || document;
  290. ele.querySelectorAll('.post-title>a[href]').forEach(function (item) {
  291. if (item.textContent.toLowerCase().includes("4wl")) {
  292. item.closest(".post-list-item").remove()
  293. }
  294. });
  295. },
  296. //拉黑用户
  297. blockMemberDOMInsert() {
  298. if (!this.loginStatus) return;
  299.  
  300. const _this = this;
  301. Array.from(document.querySelectorAll(".post-list .post-list-item,.content-item")).forEach((function (t, n) {
  302. var r = t.querySelector('.avatar-normal');
  303. r.addEventListener("click", (function (n) {
  304. n.preventDefault();
  305. let intervalId = setInterval(async () => {
  306. const userCard = document.querySelector('div.user-card.hover-user-card');
  307. const pmButton = document.querySelector('div.user-card.hover-user-card a.btn');
  308. if (userCard && pmButton) {
  309. clearInterval(intervalId);
  310. const dataVAttrs = util.getAttributesByPrefix(userCard, 'data-v');
  311. const userName = userCard.querySelector('a.Username').innerText;
  312. const blockBtn = document.createElement("a");
  313. for (let k in dataVAttrs) {
  314. blockBtn.setAttribute(k, dataVAttrs[k]);
  315. };
  316. blockBtn.onclick = function (e) { e.preventDefault(); _this.blockMember(userName) };
  317. blockBtn.className = "btn";
  318. blockBtn.style.float = "left";
  319. blockBtn.innerText = "拉黑";
  320. pmButton.after(blockBtn);
  321. }
  322. }, 50);
  323. }))
  324. }))
  325. },
  326. // 黑名单
  327. blockMember(userName) {
  328. util.post("/api/block-list/add", { "block_member_name": userName }, { "Content-Type": "application/json" }, '').then(function (data) {
  329. if (data.success) {
  330. let msg = '屏蔽用户【' + userName + '】成功!';
  331. unsafeWindow.mscAlert(msg);
  332. util.clog(msg);
  333. } else {
  334. let msg = '屏蔽用户【' + userName + '】失败!' + data.message;
  335. unsafeWindow.mscAlert(msg);
  336. util.clog(msg);
  337. }
  338. }).catch(function (err) {
  339. util.clog(err);
  340. });
  341. },
  342. addLevelTag(){//添加等级标签
  343. if (!this.loginStatus) return;
  344. if (!opts.comment.pathPattern.test(location.pathname)) return;
  345.  
  346. this.getUserInfo(unsafeWindow.__config__.postData.comments[0].poster.uid,function(user){
  347. let span= document.createElement('span');
  348. span.innerHTML=`<span>Lv ${user.rank}</span>`;
  349. span.classList=`nsk-badge role-tag user-level user-lv${user.rank}`;
  350. document.querySelector('#nsk-body .nsk-post .nsk-content-meta-info .author-info>a').after(span);
  351. });
  352. },
  353. getUserInfo(uid,callback){
  354. util.get(`/api/account/getInfo/${uid}`,{},'json').then(function(data){
  355. if(!data.success){
  356. util.clog(data);
  357. return;
  358. }
  359. callback && callback(data.detail);
  360. });
  361. },
  362. // 自动翻页
  363. autoLoading() {
  364. let opt = {};
  365. if (opts.post.pathPattern.test(location.pathname)) { opt = opts.post; }
  366. else if (opts.comment.pathPattern.test(location.pathname)) { opt = opts.comment; }
  367. else { return; }
  368. let is_requesting = false;
  369. let _this = this;
  370. this.windowScroll(function (direction, e) {
  371. if (direction === 'down') { // 下滑才准备翻页
  372. let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  373. if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + opt.scrollThreshold && !is_requesting) {
  374. if (!document.querySelector(opt.nextPagerSelector)) return;
  375. let nextUrl = document.querySelector(opt.nextPagerSelector).attributes.href.value;
  376. is_requesting = true;
  377. util.get(nextUrl, {}, 'text').then(function (data) {
  378. let doc = new DOMParser().parseFromString(data, "text/html");
  379. _this.blockPost(doc);//过滤帖子
  380. document.querySelector(opt.postListSelector).append(...doc.querySelector(opt.postListSelector).childNodes);
  381. document.querySelector(opt.topPagerSelector).innerHTML = doc.querySelector(opt.topPagerSelector).innerHTML;
  382. document.querySelector(opt.bottomPagerSelector).innerHTML = doc.querySelector(opt.bottomPagerSelector).innerHTML;
  383. history.pushState(null, null, nextUrl);
  384. is_requesting = false;
  385. }).catch(function (err) {
  386. is_requesting = false;
  387. util.clog(err);
  388. });
  389. }
  390. }
  391. });
  392. },
  393. // 滚动条事件
  394. windowScroll(fn1) {
  395. var beforeScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop,
  396. fn = fn1 || function () { };
  397. setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件
  398. window.addEventListener('scroll', function (e) {
  399. var afterScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop,
  400. delta = afterScrollTop - beforeScrollTop;
  401. if (delta == 0) return false;
  402. fn(delta > 0 ? 'down' : 'up', e);
  403. beforeScrollTop = afterScrollTop;
  404. }, false);
  405. }, 1000)
  406. },
  407. switchMultiState(stateName, states) {//多态顺序切换
  408. let currState = util.getValue(stateName);
  409. currState = (currState + 1) % states.length;
  410. util.setValue(stateName, currState);
  411. this.registerMenus();
  412. },
  413. getMenuStateText(menu, stateVal) {
  414. return `${menu.states[stateVal].s1} ${menu.text}(${menu.states[stateVal].s2})`;
  415. },
  416. _menus: [
  417. { name: opts.setting.SETTING_SIGN_IN_STATUS, callback: (name, states) => main.switchMultiState(name, states), accessKey: '', text: '自动签到', states: [{ s1: '❌', s2: '关闭' }, { s1: '🎲', s2: '随机🍗' }, { s1: '5️⃣', s2: '5个🍗' }] },
  418. { name: 'advanced_settings', callback: (name, states) => unsafeWindow.mscAlert('全力施工中...'), accessKey: '', text: '⚙️ 高级设置', states: [] },
  419. { name: 'feedback', callback: (name, states) => GM_openInTab('https://greasyfork.org/zh-CN/scripts/479426-nodeseek%E5%A2%9E%E5%BC%BA/feedback', { active: true, insert: true, setParent: true }), accessKey: '', text: '💬 反馈 & 建议', states: [] }
  420. ],
  421. _menuIds: [],
  422. registerMenus() {
  423. this._menuIds.forEach(function (id) {
  424. GM_unregisterMenuCommand(id);
  425. });
  426. this._menuIds = [];
  427.  
  428. const _this = this;
  429. this._menus.forEach(function (menu) {
  430. let k = menu.text;
  431. if (menu.states.length > 0) {
  432. k = _this.getMenuStateText(menu, util.getValue(menu.name));
  433. }
  434. let menuId = GM_registerMenuCommand(k, function () { menu.callback(menu.name, menu.states) });
  435. _this._menuIds.push(menuId);
  436. });
  437. },
  438. addPluginStyle() {
  439. let style = `
  440. .notie-container{ opacity: 0.8; }
  441. .nsplus-tip { background-color: rgba(255, 217, 0, 0.8); border: 0px solid black; padding: 10px; text-align: center;animation: blink 5s cubic-bezier(.68,.05,.46,.96) infinite;}
  442. /* @keyframes blink{ 0%{background-color: red;} 25%{background-color: yellow;} 50%{background-color: blue;} 75%{background-color: green;} 100%{background-color: red;} } */
  443. .nsplus-tip p,.nsplus-tip p a { color: #f00 }
  444. .nsplus-tip p a:hover {color: #0ff}
  445. #back-to-comment{display:flex;}
  446. #fast-nav-button-group .nav-item-btn:nth-last-child(4){bottom:120px;}
  447. .post-list .post-title a:visited{color:#681da8}
  448. .role-tag.user-level.user-lv0 {background-color: rgb(199 194 194); border: 1px solid rgb(199 194 194); color: #fafafa;}
  449. .role-tag.user-level.user-lv1 {background-color: #ff9400; border: 1px solid #ff9400; color: #fafafa;}
  450. .role-tag.user-level.user-lv2 {background-color: #ff9400; border: 1px solid #ff9400; color: #fafafa;}
  451. .role-tag.user-level.user-lv3 {background-color: #ff3a55; border: 1px solid #ff3a55; color: #fafafa;}
  452. .role-tag.user-level.user-lv4 {background-color: #ff3a55; border: 1px solid #ff3a55; color: #fafafa;}
  453. .role-tag.user-level.user-lv5 {background-color: #de00ff; border: 1px solid #de00ff; color: #fafafa;}
  454. .role-tag.user-level.user-lv6 {background-color: #de00ff; border: 1px solid #de00ff; color: #fafafa;}
  455. .role-tag.user-level.user-lv7 {background-color: #ff0000; border: 1px solid #ff0000; color: #fafafa;}
  456. .role-tag.user-level.user-lv8 {background-color: #3478f7; border: 1px solid #3478f7; color: #fafafa;}
  457. `;
  458.  
  459. if (document.head) {
  460. util.addStyle('notie-style', 'style', GM_getResourceText('notieStyle'));
  461. util.addStyle('nsplus-style', 'style', style);
  462. }
  463.  
  464. const headObserver = new MutationObserver(() => {
  465. util.addStyle('notie-style', 'style', GM_getResourceText('notieStyle'));
  466. util.addStyle('nsplus-style', 'style', style);
  467. });
  468. headObserver.observe(document.head, { childList: true, subtree: true });
  469. },
  470. init() {
  471. this.initValue();
  472. this.addPluginStyle();
  473. this.checkLogin();
  474. this.autoSignIn();//自动签到
  475. this.addSignTips();//签到提示
  476. this.autoJump();//自动点击跳转页
  477. this.autoLoading();//无缝加载帖子和评论
  478. this.openPostInNewTab();//在新标签页打开帖子
  479. this.blockMemberDOMInsert();//拉黑用户
  480. this.blockPost();//屏蔽帖子
  481. this.quickComment();//快捷评论
  482. this.addLevelTag();//添加等级标签
  483. this.registerMenus();
  484. const css = GM_getResourceText("highlightStyle");
  485. GM_addStyle(css);
  486. GM_addElement('script', {
  487. src: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js'
  488. });
  489. GM_addElement('script', {
  490. textContent: 'window.onload = function(){hljs.highlightAll();}'
  491. });
  492. }
  493. }
  494. main.init();
  495. })();