您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
load post detail information is automatically loaded when the button is clicked
- // ==UserScript==
- // @name NodeSeek+
- // @namespace http://tampermonkey.net/
- // @version 0.4.2
- // @description load post detail information is automatically loaded when the button is clicked
- // @author tsd
- // @match https://www.nodeseek.com/*
- // @match https://www.nodeseek.com/*
- // @icon https://www.nodeseek.com/static/image/favicon/android-chrome-192x192.png
- // @license GPLv3
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // @grant unsafeWindow
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_deleteValue
- // @grant GM_removeValueChangeListener
- // @grant GM_addValueChangeListener
- // @grant GM_registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // ==/UserScript==
- (function () {
- "use strict";
- console.log("script");
- //GM_setValue
- //allCollectionData 收藏的post的id列表
- //checkInTime 签到的时间
- //isRandom 是否摸奖签到
- //isAuto 是否自动签到
- //contentTime 记录点击展开回复内容div的时间
- //replyNum 当前回复数
- //blockWords 屏蔽的关键词
- //默认抽奖
- if (GM_getValue("isRandom") === undefined) {
- GM_setValue("isRandom", true);
- }
- //默认手动
- if (GM_getValue("isAuto") === undefined) {
- GM_setValue("isAuto", false);
- }
- //注册菜单
- let switchCheckType;
- let switchAutoType;
- let listenerswitchCheckType;
- let listenerswitchAutoType;
- function createMenu() {
- switchCheckType = GM_registerMenuCommand(
- GM_getValue("isRandom") === true
- ? "切换签到模式,当前为随机"
- : "切换签到模式,当前为固定",
- menuRandomClick
- );
- switchAutoType = GM_registerMenuCommand(
- GM_getValue("isAuto") === true
- ? "切换自动模式,当前为自动"
- : "切换自动模式,当前为手动",
- menuAutoClick
- );
- //是否有变动
- listenerswitchCheckType = GM_addValueChangeListener(
- "isRandom",
- function (name, old_value, new_value, remote) {
- if (old_value !== new_value) {
- mscAlert(new_value === true ? "已切换为随机" : "已切换为固定");
- }
- }
- );
- listenerswitchAutoType = GM_addValueChangeListener(
- "isAuto",
- function (name, old_value, new_value, remote) {
- if (old_value !== new_value) {
- mscAlert(new_value === true ? "已切换为自动" : "已切换为手动");
- }
- }
- );
- }
- //菜单点击刷新签到信息
- function menuRandomClick() {
- GM_unregisterMenuCommand(switchCheckType);
- GM_getValue("isRandom") === true
- ? GM_setValue("isRandom", false)
- : GM_setValue("isRandom", true);
- //重新注册
- GM_removeValueChangeListener(listenerswitchCheckType);
- GM_removeValueChangeListener(listenerswitchAutoType);
- createMenu();
- checkIn();
- }
- //菜单点击刷新自动信息
- function menuAutoClick() {
- GM_unregisterMenuCommand(switchAutoType);
- GM_getValue("isAuto") === true
- ? GM_setValue("isAuto", false)
- : GM_setValue("isAuto", true);
- //重新注册
- GM_removeValueChangeListener(listenerswitchCheckType);
- GM_removeValueChangeListener(listenerswitchAutoType);
- createMenu();
- checkIn();
- }
- // 检查是否登陆
- let loginStatus = false;
- // 查看手机情况
- let mobileStatus = false;
- if (document.querySelector(".user-head")) {
- loginStatus = true;
- }
- // 检查屏蔽关键词
- blockPost();
- if(!document.querySelector("#nsk-right-panel-container>.user-card")){
- mobileStatus = true;
- }
- if (loginStatus) {
- //注册油猴菜单
- createMenu();
- //处理登录;
- checkIn();
- //维护一个全部的收藏id列表
- if (GM_getValue("allCollectionData") === undefined) {
- loadUntilEmpty();
- }
- } else {
- //清除收藏的post的id列表
- //GM_deleteValue("allCollectionData");
- //清除签到的时间
- //GM_deleteValue("checkInTime");
- //清除签到方式
- //GM_deleteValue("isRandom");
- //清除自动方式
- //GM_deleteValue("isAuto");
- }
- //签到判断
- function checkIn() {
- let timeNow =
- new Date().getFullYear() +
- "/" +
- (new Date().getMonth() + 1) +
- "/" +
- new Date().getDate();
- let oldTime = GM_getValue("checkInTime");
- if (!oldTime || oldTime !== timeNow) {
- //允许执行签到
- if (GM_getValue("isAuto") === true) {
- //执行自动签到
- getChicken(GM_getValue("isRandom")).then((responseData) => {
- if (responseData.success === true) {
- //签到成功之后存下时间
- GM_setValue("checkInTime", timeNow);
- console.log(`[NodeSeek] 签到:`, responseData.message);
- } else if (responseData.message === "今天已完成签到,请勿重复操作") {
- //存下时间
- GM_setValue("checkInTime", timeNow);
- console.log(`[NodeSeek] 签到:`, responseData.message);
- } else {
- console.error("Error in checkIn:", error);
- }
- });
- } else {
- //执行手动签到
- //处理按钮
- let right_panel = document.querySelector("#nsk-right-panel-container");
- let new_check = document.createElement("div");
- let publish_btn = document.querySelector(".btn.new-discussion");
- let publish_btn_parent = publish_btn.parentNode;
- new_check.innerHTML = '<a class="btn new-discussion">签到</a>';
- //展示签到按钮
- right_panel.insertBefore(new_check, publish_btn_parent);
- setupCursorStyle(new_check);
- new_check.onclick = function () {
- getChicken(GM_getValue("isRandom")).then((responseData) => {
- console.log(responseData.message);
- if (responseData.success === true) {
- //签到成功之后存下时间
- GM_setValue("checkInTime", timeNow);
- //弹窗示意多少鸡腿
- mscAlert(responseData.message);
- //隐藏
- new_check.style.display = "none";
- } else if (
- responseData.message === "今天已完成签到,请勿重复操作"
- ) {
- //存下时间
- GM_setValue("checkInTime", timeNow);
- mscAlert(responseData.message);
- //隐藏
- new_check.style.display = "none";
- } else {
- console.error("Error in checkIn:", error);
- }
- });
- };
- }
- } else {
- //返回已经签到按钮或隐藏
- }
- }
- // 签到
- async function getChicken(random) {
- const url = `https://www.nodeseek.com/api/attendance?random=${random}`;
- const data = {
- random: random,
- };
- try {
- const responseData = await postData(url, data);
- return responseData;
- } catch (error) {
- console.error("Error in getChicken:", error);
- return null;
- }
- }
- //自定义屏蔽词窗口
- let modal = document.createElement('div');
- let modalContent = document.createElement('div');
- let closeBtn = document.createElement('span');
- let promptText = document.createElement('p');
- let inputField = document.createElement('input');
- let submitBtn = document.createElement('button');
- // 设置元素属性和内容
- modal.id = 'myModal';
- modal.className = 'modal';
- modalContent.className = 'modal-content';
- closeBtn.className = 'close';
- closeBtn.textContent = '×';
- promptText.textContent = '请输入要屏蔽的关键词,多个关键词用逗号隔开(注意:严格区分,最好是复制过来)';
- inputField.id = 'block-input';
- inputField.type = 'text';
- submitBtn.id = 'submit-button';
- submitBtn.textContent = '确定';
- // 将所有元素添加到屏蔽词窗口中
- modalContent.appendChild(closeBtn);
- modalContent.appendChild(promptText);
- modalContent.appendChild(inputField);
- modalContent.appendChild(submitBtn);
- modal.appendChild(modalContent);
- function createBlockWordsModal() {
- document.body.appendChild(modal);
- modal.style.display = "block";
- }
- // 自定义屏蔽词
- let blockDiv = document.querySelector(".sorter");
- let btnBlock = document.createElement("button");
- btnBlock.style.cursor = 'pointer';
- btnBlock.innerText = "关键词屏蔽";
- btnBlock.classList.add("btnBlock-post");
- if(blockDiv !== null){
- blockDiv.parentNode.insertBefore(btnBlock, blockDiv.nextSibling);
- }
- // 弹窗输入屏蔽词
- function getOldBlockWords() {
- let oldBlockWords = GM_getValue("blockWords");
- inputField.value = oldBlockWords ? oldBlockWords : '';
- modal.style.display = 'block';
- }
- // 当用户点击 "确定" 按钮,获取输入值
- submitBtn.onclick = function() {
- let blockWords = inputField.value.trim();
- GM_setValue("blockWords", blockWords);
- modal.style.display = 'none';
- if (!blockWords) {
- window.location.reload();
- } else {
- blockPost();
- }
- }
- // 当用户点击屏蔽词窗口外的任何地方或 "x" 图标,关闭屏蔽词窗口
- closeBtn.onclick = window.onclick = function(event) {
- if (event.target == modal || event.target == closeBtn) {
- modal.style.display = 'none';
- }
- }
- // 点击按钮时,显示屏蔽词窗口
- btnBlock.onclick = function () {
- createBlockWordsModal();
- getOldBlockWords();
- };
- //屏蔽帖子
- function blockPost() {
- //获取自定义的屏蔽词
- let blockWords = GM_getValue("blockWords");
- blockWords = blockWords === undefined ? '':blockWords.trim();
- if (blockWords) {
- let blockWordsArr = blockWords.split(",");
- let lists = document.querySelectorAll(".post-list");
- lists.forEach((list) => {
- let items = list.childNodes;
- items.forEach((element) => {
- let post_item = element.querySelector(".post-title>a");
- let post_title = post_item.innerText;
- blockWordsArr.forEach((word) => {
- if (post_title.includes(word)) {
- element.classList.add('blocked-post');
- }
- });
- });
- });
- }
- }
- // 查看内容时的标签顺序样式修改
- let footTag = document.querySelectorAll(".floor-link");
- footTag.forEach((item) =>{
- item.className = "foot-tag";
- let itemChild = item.firstChild.textContent;
- item.firstChild.textContent = itemChild.replace(/^#/, "")
- })
- //查看帖子中的回复消息
- initializePage();
- // 定义一个函数来发送GET请求
- async function loadData(page) {
- const url = `https://www.nodeseek.com/api/statistics/list-collection?page=${page}`;
- try {
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- const data = await response.json();
- return data;
- } catch (error) {
- console.error("Error:", error);
- return null;
- }
- }
- //POST请求
- async function postData(url = "", data = {}) {
- try {
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(data),
- });
- const responseData = await response.json();
- return responseData;
- } catch (error) {
- console.error("Error in postData:", error);
- }
- }
- async function loadUntilEmpty(page = 1) {
- //收藏列表数组
- let allCollectionData = [];
- while (true) {
- const data = await loadData(page);
- data.collections.forEach((item) => {
- // 将获取到的数据加到数组中
- allCollectionData.push(item.post_id);
- });
- // 如果没有获取到数据或获取到的数据为空,停止加载
- if (!data || data.collections.length === 0) {
- //丢进去方便存取
- GM_setValue("allCollectionData", allCollectionData);
- break;
- }
- page++;
- }
- }
- function initializePage() {
- let lists = document.querySelectorAll(".post-list");
- lists.forEach((list) => {
- let items = list.childNodes;
- items.forEach((element) => {
- setupPostItem(element);
- });
- });
- }
- function setupPostItem(element) {
- let post_item = element.querySelector(".post-title>a");
- let new_div = document.createElement("span");
- if(mobileStatus){
- new_div.className = "info-triganle-mobile";
- }else{
- new_div.className = "info-triganle";
- }
- new_div.innerHTML = '<span class="triangle">▼</span>';
- element.querySelector(".post-info").append(new_div);
- setupCursorStyle(new_div);
- new_div.onclick = function () {
- if(GM_getValue("contentTime") + 1000 >= Date.now()){
- console.warn("请勿重复点击");
- }else{
- GM_setValue("contentTime",Date.now());
- GM_setValue("replyNum",element.querySelector(".info-item.info-comments-count > span").innerText);
- togglePostContent(post_item, element, new_div);
- }
- };
- }
- function togglePostContent(post_item, element, new_div) {
- let id = post_item.href.replace("https://www.nodeseek.com", "");
- let content = document.getElementById(id);
- if (content) {
- toggleDisplay(content, new_div);
- } else {
- new_div.firstElementChild.innerText = "○";
- document.body.style.cursor = "wait";
- new_div.firstElementChild.className = "content-loaded";
- fetchContent(post_item.href, element, (contents, targetEle) => {
- insertContentAfter(contents, targetEle);
- loadNextPage(contents, targetEle, 1);
- new_div.firstElementChild.innerText = "▲";
- document.body.style.cursor = "auto";
- });
- }
- }
- //显隐箭头
- function toggleDisplay(content, new_div) {
- if (content.style.display === "none") {
- content.style.display = "block";
- new_div.firstElementChild.innerText = "▲";
- } else {
- content.style.display = "none";
- new_div.firstElementChild.innerText = "▼";
- }
- }
- //获取div框中的内容
- function fetchContent(url, targetEle, callback) {
- const xhr = new XMLHttpRequest();
- xhr.open("GET", url, true);
- xhr.onload = function () {
- if (xhr.status !== 200) return;
- const tempContainer = document.createElement("div");
- tempContainer.innerHTML = xhr.responseText;
- const contents = createContentDiv(url);
- const post_contents = tempContainer.querySelectorAll(".post-content");
- const colloct = appendPostContentBox(contents);
- post_contents.forEach((e) => {
- modifyFootTagDivStyle(e);
- contents.firstChild.appendChild(e.parentElement);
- });
- if (callback && typeof callback === "function") {
- callback(contents, targetEle);
- }
- };
- xhr.send();
- }
- function createContentDiv(url) {
- const contents = document.createElement("div");
- contents.id = url.replace("https://www.nodeseek.com", "");
- contents.className = "content-div";
- return contents;
- }
- function appendPostContentBox(contents) {
- contents.innerHTML += '<div class="post-content-box"></div>';
- const colloct = contents.firstChild;
- colloct.innerHTML +=
- '<div data-v-372de460="" class="comment-menu">' +
- '<div data-v-372de460="" title="收藏" class="menu-item"><svg data-v-372de460="" class="iconpark-icon"><use data-v-372de460="" href="#star-6negdgdk"></use></svg></div>' +
- "</div>";
- const icon = colloct.firstElementChild.querySelector(".menu-item");
- const postId = getPostId(contents.id);
- const is_collected = GM_getValue("allCollectionData").some(
- (item) => item === postId
- );
- if (is_collected) {
- icon.style.color = "red";
- }
- setupCursorStyle(icon);
- icon.onclick = function () {
- colloctContent(postId, colloct);
- };
- return colloct;
- }
- function getPostId(id) {
- const regex = /\/post-(\d+)-1/;
- const match = id.match(regex);
- if (match != null) {
- return parseInt(match[1]);
- }
- return null;
- }
- function modifyFootTagDivStyle(e) {
- const footTagDiv = e.parentElement.querySelector(".floor-link");
- footTagDiv.className = "foot-tag-div";
- const itemChild = footTagDiv.textContent;
- footTagDiv.textContent = itemChild.replace(/^#/, "")
- }
- //帖子的收藏处理
- function colloctContent(post_id, colloct) {
- let icon = colloct.firstElementChild.querySelector(".menu-item");
- if (icon.style.color === "red") {
- //取消收藏处理
- let result = confirm("您确定要取消收藏吗?");
- if (result) {
- collection_del("remove", post_id).then((success) => {
- if (success === true) {
- icon.style.color = "";
- //维护一个全部的收藏id列表
- loadUntilEmpty();
- }
- });
- }
- } else {
- //收藏帖子
- collection_add("add", post_id).then((success) => {
- if (success === true) {
- icon.style.color = "red";
- //维护一个全部的收藏id列表
- loadUntilEmpty();
- }
- });
- }
- }
- //收藏方法
- async function collection_add(action_type, post_id) {
- const url = "https://www.nodeseek.com/api/statistics/collection";
- const data = {
- action: action_type,
- postId: post_id,
- };
- try {
- const responseData = await postData(url, data);
- if (responseData && responseData.success === true) {
- mscAlert("收藏成功!");
- }
- // else if (responseData && responseData.success === false) {
- // alert("你已经收藏过了!");
- // }
- return responseData ? responseData.success : null;
- } catch (error) {
- console.error("Error in collection_add:", error);
- return null;
- }
- }
- //取消收藏方法
- async function collection_del(action_type, post_id) {
- const url = "https://www.nodeseek.com/api/statistics/collection";
- const data = {
- action: action_type,
- postId: post_id,
- };
- try {
- const responseData = await postData(url, data);
- if (responseData && responseData.success === true) {
- mscAlert("取消收藏成功!");
- }
- return responseData ? responseData.success : null;
- } catch (error) {
- console.error("Error in collection_del:", error);
- return null;
- }
- }
- function insertContentAfter(content, targetEle) {
- let ul = targetEle.parentNode;
- ul.insertBefore(content, targetEle.nextSibling);
- }
- function loadNextPage(contentDiv, targetEle, currentPage) {
- if(GM_getValue("replyNum") / 10 <= currentPage){
- return;
- }
- let nextPage = currentPage + 1;
- let nextPageUrl = targetEle
- .querySelector(".post-title>a")
- .href.replace(/(\d+)$/, nextPage);
- fetchContent(nextPageUrl, targetEle, (nextContents, targetEle) => {
- let postContentBox = contentDiv.querySelector(".post-content-box");
- if (nextContents.querySelector(".post-content")) {
- let nextPostContents = nextContents.querySelectorAll(".post-content");
- nextPostContents.forEach((e) => {
- postContentBox.appendChild(e.parentElement);
- });
- // 递归调用以加载后续页面,延迟1秒
- setTimeout(() => {
- loadNextPage(contentDiv, targetEle, nextPage);
- }, 1000);
- }
- });
- }
- function setupCursorStyle(element) {
- element.addEventListener("mouseover", function () {
- document.body.style.cursor = "pointer";
- });
- element.addEventListener("mouseout", function () {
- document.body.style.cursor = "auto";
- });
- }
- let css = `
- .content-div {
- height: 600px;
- padding: 20px;
- margin: 10px auto;
- border: 1px solid gray;
- border-radius: 10px;
- overflow: scroll;
- }
- .post-content-box {
- border-bottom: 2px dashed gray;
- padding-bottom: 10px;
- margin-bottom: 10px;
- }
- .triangle {
- font-size: medium;
- color: gray;
- }
- .info-triganle{
- position: absolute;
- right: 54px;
- }
- .info-triganle-mobile{
- position: absolute;
- }
- .content-loaded {
- font-size: medium;
- color: red;
- }
- ::-webkit-scrollbar {
- width: 6px;
- height: 6px;
- }
- ::-webkit-scrollbar-track {
- border-radius: 3px;
- background: rgba(0,0,0,0.06);
- -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.08);
- }
- ::-webkit-scrollbar-thumb {
- border-radius: 3px;
- background: rgba(0,0,0,0.12);
- -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.2);
- }
- .foot-tag{
- margin-left: 1rem;
- line-height: 0.5rem;
- border-radius: 0.5rem;
- display: inline-block;
- background-color: #f0f0f0;
- color: #bdbdbd;
- padding: 3px 9px;
- cursor: default;
- }
- .foot-tag-div{
- margin-left: 1rem;
- line-height: 0.5rem;
- border-radius: 0.5rem;
- display: inline-block;
- background-color: #f0f0f0;
- color: #bdbdbd;
- padding: 3px 9px;
- cursor: default;
- }
- .preview {
- margin: 1rem 0;
- border: 1px solid transparent;
- border-radius: 8px;;
- cursor: pointer;
- }
- .preview:hover {
- border: 1px solid #c8c8c8;
- }
- .preview > .post-content {
- height: 200px !important;
- margin-top: 0.5rem !important;
- }
- .preview > .post-content.show-all {
- max-height: 200px;
- -webkit-mask-image:none;
- }
- .preview .topic-link:link {
- color: black !important;
- }
- .btnBlock-post{
- background-color: #888;
- border: 1px solid #737373;
- border-radius: 3px;
- display: inline-flex;
- margin: 0 8px;
- position: absolute;
- color: var(--bg-main-color);
- left: 15%;
- }
- /* 屏蔽框 */
- .modal {
- display: none;
- position: fixed;
- z-index: 1;
- padding-top: 100px;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- background-color: rgba(0,0,0,0.4);
- }
- .modal-content {
- height: 15%;
- background-color: #fefefe;
- margin: auto;
- padding: 20px;
- border: 1px solid #888;
- width: 60%;
- border-radius: 15px;
- box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
- }
- .close {
- color: #aaaaaa;
- float: right;
- font-size: 28px;
- font-weight: bold;
- }
- .close:hover,
- .close:focus {
- color: #000;
- text-decoration: none;
- cursor: pointer;
- }
- .modal p {
- font-size: 18px;
- font-weight: bold;
- }
- #block-input {
- width: 100%;
- padding: 12px 20px;
- margin: 8px 0;
- box-sizing: border-box;
- border: 2px solid #ccc;
- border-radius: 4px;
- background-color: #f8f8f8;
- resize: none;
- }
- #submit-button {
- background-color: #4CAF50;
- color: white;
- padding: 10px 33px;
- text-align: center;
- text-decoration: none;
- display: block;
- font-size: 16px;
- margin: 8px 2px;
- cursor: pointer;
- border: none;
- border-radius: 4px;
- width: auto;
- float: right;
- }
- @media screen and (max-width: 600px) {
- .modal-content {
- width: 90%;
- height: 16%;
- }
- .btnBlock-post{
- background-color: #888;
- border: 1px solid #737373;
- border-radius: 3px;
- display: inline-flex;
- margin: 0 8px;
- position: absolute;
- color: var(--bg-main-color);
- left: 30%;
- }
- }
- `;
- GM_addStyle(css);
- })();