// ==UserScript== // @name NodeSeek增强 // @namespace http://www.nodeseek.com/ // @version 0.3-alpha // @description 自动签到、自动滚动翻页 // @author dabao // @match *://www.nodeseek.com/* // @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= // @require https://cdn.staticfile.org/notie/4.3.1/notie.min.js // @resource notieStyle https://cdn.staticfile.org/notie/4.3.1/notie.min.css // @resource highlightStyle https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getResourceText // @grant GM_addElement // @grant GM_addStyle // @grant unsafeWindow // @run-at document-end // @license GPL-3.0 License // @supportURL https://www.nodeseek.com/notification#/message?mode=talk&to=8110 // @homepageURL https://www.nodeseek.com/post-36263-1 // @downloadURL none // ==/UserScript== (function () { 'use strict'; const util = { clog(c) { console.group("%c %c [NodeSeek增强]", `background:url(${GM_info.script.icon}) center center no-repeat;background-size:12px;padding:3px`, ""); console.log(c); console.groupEnd(); }, parseQuery(name) { let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); let r = location.search.substr(1).match(reg); if (r != null) return (r[2]); return null; }, getValue(name) { return GM_getValue(name); }, setValue(name, value) { GM_setValue(name, value); }, sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); }, addStyle(id, tag, css) { tag = tag || 'style'; let doc = document, styleDom = doc.getElementById(id); if (styleDom) return; let style = doc.createElement(tag); style.rel = 'stylesheet'; style.id = id; tag === 'style' ? style.innerHTML = css : style.href = css; document.head.appendChild(style); }, isHidden(el) { try { return el.offsetParent === null; } catch (e) { return false; } }, query(selector) { if (Array.isArray(selector)) { let obj = null; for (let i = 0; i < selector.length; i++) { let o = document.querySelector(selector[i]); if (o) { obj = o; break; } } return obj; } return document.querySelector(selector); }, getAttributesByPrefix(element, prefix) { var attributes = element.attributes; var matchingAttributes = {}; for (var attribute of attributes) { var attributeName = attribute.name; var attributeValue = attribute.value; if (attributeName.startsWith(prefix)) { matchingAttributes[attributeName] = attributeValue; } } return matchingAttributes; }, openLinkInNewTab(selector) { var allLinks = document.querySelectorAll(selector); allLinks.forEach(function (link) { link.setAttribute('target', '_blank'); }); } }; const opts = { post: { pathPattern: /^\/(categories\/|page|award|$)/, scrollThreshold: 200, nextPagerSelector: '.nsk-pager a.pager-next', postListSelector: 'ul.post-list', topPagerSelector: 'div.nsk-pager.pager-top', bottomPagerSelector: 'div.nsk-pager.pager-bottom', }, comment: { pathPattern: /^\/post-/, scrollThreshold: 690, nextPagerSelector: '.nsk-pager a.pager-next', postListSelector: 'ul.comments', topPagerSelector: 'div.nsk-pager.post-top-pager', bottomPagerSelector: 'div.nsk-pager.post-bottom-pager', }, setting: { SETTING_SIGN_IN_STATUS: 'setting_sign_in_status' } }; let main = { // 初始化配置数据 initValue() { let value = [{ name: opts.setting.SETTING_SIGN_IN_STATUS, value: 0 }]; value.forEach((v) => { if (util.getValue(v.name) === undefined) { util.setValue(v.name, v.value); } }); }, loginStatus: false, //检查是否登陆 checkLogin() { if (document.querySelector('#nsk-right-panel-container>.user-card')) { this.loginStatus = true; util.clog('已登录'); } }, // 自动签到 autoSignIn(rand) { if (!this.loginStatus) return let localTimezoneOffset = (new Date()).getTimezoneOffset(); let beijingOffset = 8 * 60; let beijingTime = new Date(Date.now() + (localTimezoneOffset + beijingOffset) * 60 * 1000); let timeNow = `${beijingTime.getFullYear()}/${(beijingTime.getMonth() + 1)}/${beijingTime.getDate()}`, timeOld = util.getValue('menu_signInTime'); if (!timeOld || timeOld != timeNow) { // 是新的一天 util.setValue('menu_signInTime', timeNow); // 写入签到时间以供后续比较 GM_xmlhttpRequest({ url: '/api/attendance?random=' + (rand || true), method: 'POST', timeout: 4000 , onload: function (res) { if (res.status === 200) { let json = JSON.parse(res.responseText); if (json.success) { GM_notification({ text: '签到成功!今天午饭+' + json.gain + '个鸡腿; 积攒了' + json.current + '个鸡腿了', timeout: 3500 }); } else { GM_notification({ text: '签到失败!' + json.message, timeout: 3500 }); } } }, onerror: function (err) { util.clog('error'); util.clog(err) } }); util.clog(`[NodeSeek] 签到完成`); } }, addSignTips() { let tip = document.createElement('div'); tip.className = "nsplus-tip"; let tip_p = document.createElement('p'); tip_p.innerHTML = '今天你还没有签到哦! 【随机抽个鸡腿】 【只要5个鸡腿】 【今天不再提示】'; tip.appendChild(tip_p); document.querySelector('#nsk-frame').before(tip); }, quickComment() { let _this = this; 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() } }) }, addEditorCloseButton() { var linkElement = document.createElement('a'); // 设置属性 linkElement.setAttribute('data-v-f5a54ae2', ''); linkElement.setAttribute('href', 'javascript:void(0)'); linkElement.setAttribute('title', '关闭'); linkElement.setAttribute('class', 'editor-top-button'); // 创建 元素 var spanElement = document.createElement('span'); spanElement.setAttribute('data-v-f5a54ae2', ''); spanElement.setAttribute('class', 'i-icon i-icon-close'); spanElement.innerHTML = ''; // 将元素组合起来 linkElement.appendChild(spanElement); linkElement.addEventListener("click", function (e) { var md = document.querySelector('.md-editor'); md.style.position = ""; md.style.bottom = ""; md.style.maxWidth = ""; this.remove(); }); document.querySelector('#editor-body > div.tab-select.window_header > a[title=全屏]').after(linkElement); }, //新窗口打开帖子 openPostInNewTab() { util.openLinkInNewTab('.post-title>a[href]'); }, //自动点击跳转页链接 autoJump() { if (!/^\/jump/.test(location.pathname)) return; document.querySelector('.btn').click(); }, blockPost(ele) { ele = ele || document; ele.querySelectorAll('.post-title>a[href]').forEach(function (item) { if (item.textContent.toLowerCase().includes("__key__")) { item.closest(".post-list-item").remove() } }); }, //拉黑用户 blockMemberDOMInsert() { Array.from(document.querySelectorAll(".post-list .post-list-item,.content-item")).forEach((function (t, n) { var r = t.querySelector('.avatar-normal'); r.addEventListener("click", (function (n) { n.preventDefault(); let intervalId = setInterval(async () => { const userCard = document.querySelector('div.user-card.hover-user-card'); const pmButton = document.querySelector('div.user-card.hover-user-card a.btn'); if (userCard && pmButton) { clearInterval(intervalId); const dataVAttrs = util.getAttributesByPrefix(userCard, 'data-v'); const userName = userCard.querySelector('a.Username').innerText; const blockBtn = document.createElement("a"); for (let k in dataVAttrs) { blockBtn.setAttribute(k, dataVAttrs[k]); }; blockBtn.onclick = function (e) { e.preventDefault(); main.blockMember(userName) }; blockBtn.className = "btn"; blockBtn.style.float = "left"; blockBtn.innerText = "拉黑"; pmButton.after(blockBtn); } }, 50); })) })) }, // 黑名单 blockMember(userName) { GM_xmlhttpRequest({ url: "/api/block-list/add", method: 'POST', headers: { "Content-Type": "application/json" }, data: JSON.stringify({ "block_member_name": userName }), onload: function (res) { if (res.status === 200) { let result = JSON.parse(res.responseText); if (result.success) { let msg = '屏蔽用户【' + userName + '】成功!'; unsafeWindow.mscAlert(msg); util.clog(msg); } else { let msg = '屏蔽用户【' + userName + '】失败!' + result.message; unsafeWindow.mscAlert(msg); util.clog(msg); } } }, onerror: function (err) { util.clog(err); } }); }, // 自动翻页 autoLoading() { let opt = {}; if (opts.post.pathPattern.test(location.pathname)) { opt = opts.post; } else if (opts.comment.pathPattern.test(location.pathname)) { opt = opts.comment; } else { return; } let is_requesting = false; let _this = this; this.windowScroll(function (direction, e) { if (direction === 'down') { // 下滑才准备翻页 let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop; if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + opt.scrollThreshold && !is_requesting) { if (!document.querySelector(opt.nextPagerSelector)) return; let nextUrl = document.querySelector(opt.nextPagerSelector).attributes.href.value; is_requesting = true; GM_xmlhttpRequest({ url: nextUrl, method: 'GET', onload: function (res) { if (res.status === 200) { let doc = new DOMParser().parseFromString(res.responseText, "text/html"); _this.blockPost(doc);//过滤帖子 document.querySelector(opt.postListSelector).append(...doc.querySelector(opt.postListSelector).childNodes); document.querySelector(opt.topPagerSelector).innerHTML = doc.querySelector(opt.topPagerSelector).innerHTML; document.querySelector(opt.bottomPagerSelector).innerHTML = doc.querySelector(opt.bottomPagerSelector).innerHTML; history.pushState(null, null, nextUrl); } is_requesting = false; }, onerror: function (err) { is_requesting = false; util.clog(err); } }); } } }); }, // 滚动条事件 windowScroll(fn1) { var beforeScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop, fn = fn1 || function () { }; setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件 window.addEventListener('scroll', function (e) { var afterScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop, delta = afterScrollTop - beforeScrollTop; if (delta == 0) return false; fn(delta > 0 ? 'down' : 'up', e); beforeScrollTop = afterScrollTop; }, false); }, 1000) }, switchMultiState(stateName, states) {//多态顺序切换 let currState = util.getValue(stateName); currState = (currState + 1) % states.length; util.setValue(stateName, currState); this.registerMenus(); }, getMenuStateText(menu, stateVal) { return `${menu.states[stateVal].k} ${menu.text}(${menu.states[stateVal].v})`; }, _menus: [{ name: opts.setting.SETTING_SIGN_IN_STATUS, callback: (name,states)=>main.switchMultiState(name,states), accessKey: '', text: '自动签到', states: [{ k: '❌', v: '关闭' }, { k: '🎲', v: '随机🍗' }, { k: '5️⃣', v: '5个🍗' }] }],//type:"b"--boolean;type:"m"--multi state _menuIds: [], registerMenus() { this._menuIds.forEach(function (id) { GM_unregisterMenuCommand(id); }); this._menuIds = []; const _this = this; this._menus.forEach(function (menu) { let k = menu.name; if (menu.states.length>0) { k = _this.getMenuStateText(menu, util.getValue(menu.name)); } let menuId = GM_registerMenuCommand(k, function(){ menu.callback(menu.name,menu.states)}); _this._menuIds.push(menuId); }); }, addPluginStyle() { let style = ` .notie-container{ opacity: 0.8; } .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;} /* @keyframes blink{ 0%{background-color: red;} 25%{background-color: yellow;} 50%{background-color: blue;} 75%{background-color: green;} 100%{background-color: red;} } */ .nsplus-tip p,.nsplus-tip p a { color: #f00 } .nsplus-tip p a:hover {color: #0ff} `; if (document.head) { util.addStyle('notie-style', 'style', GM_getResourceText('notieStyle')); util.addStyle('nsplus-style', 'style', style); } const headObserver = new MutationObserver(() => { util.addStyle('notie-style', 'style', GM_getResourceText('notieStyle')); util.addStyle('nsplus-style', 'style', style); }); headObserver.observe(document.head, { childList: true, subtree: true }); }, init() { this.initValue(); this.addPluginStyle(); this.checkLogin(); this.autoSignIn();//自动签到 this.autoJump();//自动点击跳转页 this.autoLoading();//无缝加载帖子和评论 this.openPostInNewTab();//在新标签页打开帖子 this.blockMemberDOMInsert();//拉黑用户 this.blockPost();//屏蔽帖子 this.quickComment();//快捷评论 util.getValue(opts.setting.SETTING_SIGN_IN_STATUS) === 0 && this.addSignTips();//签到提示 this.registerMenus(); const css = GM_getResourceText("highlightStyle"); GM_addStyle(css); GM_addElement('script', { src: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js' }); GM_addElement('script', { textContent: 'window.onload = function(){hljs.highlightAll();}' }); } } main.init(); })();