// ==UserScript==// @name NodeSeek 用户信誉评分系统 + 圣诞帽// @namespace http://www.nodeseek.com/// @version 1.1.0// @description 为 NodeSeek 用户显示信誉评分,基于等级、注册时间、发帖数、评论数等多维度评估。圣诞节特别版:给所有头像戴上圣诞帽!// @author Your Name// @match *://www.nodeseek.com/*// @match *://www.deepflood.com/*// @require https://s4.zstatic.net/ajax/libs/layui/2.9.9/layui.min.js// @grant unsafeWindow// @run-at document-end// @license GPL-3.0 License// ==/UserScript==(function () { "use strict"; const BASE_URL = location.origin; // 工具函数 const util = { // 创建 DOM 元素 createElement(tagName, options = {}, children = []) { const { staticClass = "", attrs = {}, on = {} } = options; const ele = document.createElement(tagName); if (staticClass) { staticClass.split(" ").forEach((cls) => ele.classList.add(cls.trim())); } Object.entries(attrs).forEach(([key, value]) => { if (key === "style" && typeof value === "object") { Object.entries(value).forEach(([styleKey, styleValue]) => { ele.style[styleKey] = styleValue; }); } else { if (value !== undefined) ele.setAttribute(key, value); } }); Object.entries(on).forEach(([event, handler]) => { ele.addEventListener(event, handler); }); children.forEach((child) => { if (typeof child === "string") { child = document.createTextNode(child); } ele.appendChild(child); }); return ele; }, // 异步请求 async get(url, headers = {}, responseType = "json") { const options = { method: "GET", headers: { "Content-Type": "application/json", ...headers }, }; const response = await fetch( url.startsWith("http") ? url : BASE_URL + url, options ); const result = await response[responseType]().catch(() => null); return response.ok ? result : Promise.reject(result); }, }; // 圣诞帽装饰系统 const ChristmasHat = { // 圣诞帽图片 - 使用用户提供的图片链接 hatImage: "https://i.111666.best/image/6hmftZOIGAsa0zNcjjqVcN.png", // 为头像添加圣诞帽 addHatToAvatar(avatarWrapper) { // 检查是否已经添加过帽子 if (avatarWrapper.querySelector(".christmas-hat")) return; // 创建帽子元素 const hat = document.createElement("img"); hat.className = "christmas-hat"; hat.src = this.hatImage; // 添加加载和错误监听 hat.onload = () => { console.log("[圣诞帽] 图片加载成功:", hat.src); }; hat.onerror = () => { console.error("[圣诞帽] 图片加载失败,使用SVG备用方案"); // 使用 SVG data URI 作为备用方案(保证能显示) hat.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23ff0000'/%3E%3Cstop offset='1' stop-color='%23cc0000'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M60 120Q60 80 80 70Q100 60 120 70Q140 80 140 120Z' fill='url(%23g)'/%3E%3Cpath d='M80 70Q90 30 100 15Q110 30 120 70' fill='url(%23g)'/%3E%3Cellipse cx='100' cy='120' rx='45' ry='10' fill='%23fff'/%3E%3Cellipse cx='100' cy='85' rx='25' ry='6' fill='%23fff'/%3E%3Ccircle cx='100' cy='15' r='15' fill='%23fff'/%3E%3C/svg%3E`; }; hat.style.cssText = ` position: absolute; top: -40%; left: 8%; width: 80%; height: auto; pointer-events: none; z-index: 10; transform: rotate(15deg); filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.5)); `; avatarWrapper.appendChild(hat); console.log("[圣诞帽] 已添加到头像容器"); }, // 给所有头像添加圣诞帽 addHatsToAllAvatars() { const avatarWrappers = document.querySelectorAll(".avatar-wrapper"); console.log(`[圣诞帽] 找到 ${avatarWrappers.length} 个头像容器`); if (avatarWrappers.length === 0) { // 如果找不到 .avatar-wrapper,尝试查找其他可能的选择器 console.warn("[圣诞帽] 未找到 .avatar-wrapper,尝试其他选择器..."); const avatars = document.querySelectorAll(".avatar-normal"); console.log(`[圣诞帽] 找到 ${avatars.length} 个 .avatar-normal 元素`); } avatarWrappers.forEach((wrapper) => { // 确保 wrapper 是相对定位 if (getComputedStyle(wrapper).position === "static") { wrapper.style.position = "relative"; } this.addHatToAvatar(wrapper); }); }, // 监听 DOM 变化,为新出现的头像添加圣诞帽 observeNewAvatars() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // 元素节点 // 检查添加的节点本身是否是 avatar-wrapper if (node.classList?.contains("avatar-wrapper")) { if (getComputedStyle(node).position === "static") { node.style.position = "relative"; } this.addHatToAvatar(node); } // 检查添加的节点内部是否包含 avatar-wrapper const wrappers = node.querySelectorAll?.(".avatar-wrapper"); wrappers?.forEach((wrapper) => { if (getComputedStyle(wrapper).position === "static") { wrapper.style.position = "relative"; } this.addHatToAvatar(wrapper); }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true, }); }, // 初始化圣诞帽系统 init() { console.log("[圣诞帽装饰] 正在添加圣诞帽..."); // 立即给现有头像添加帽子 this.addHatsToAllAvatars(); // 监听新的头像出现 this.observeNewAvatars(); // 页面加载完成后再检查一次 setTimeout(() => { this.addHatsToAllAvatars(); }, 1000); console.log("[圣诞帽装饰] 圣诞帽已添加完成!"); }, }; // 信誉评分系统 const CreditSystem = { // 根据积分计算等级 getRankByCoin(coin) { if (!coin || coin < 0) return 0; return Math.floor(Math.sqrt(coin) / 10); }, // 计算用户信誉度 calculateCredit(rank, days, posts, comments, fans, roles) { // 检查负面角色 if (roles && roles.length > 0) { const hasRole = (name) => roles.some((r) => r.name?.toLowerCase() === name); if (hasRole("banned")) return 0; // 违规禁止直接0分 } // 基础分:等级占35分 let baseScore = Math.min(rank * 3.5, 35); // 时间分:最高40分(指数衰减函数,鼓励长期用户) let timeScore = 40 * (1 - Math.exp(-days / 365)); // 帖子分:最高8分 let postScore = 8 * (1 - Math.exp(-posts / 50)); // 评论分:最高7分 let commentScore = 7 * (1 - Math.exp(-comments / 200)); // 粉丝分:最高5分(受欢迎程度) let fansScore = 5 * (1 - Math.exp(-fans / 20)); // 综合计算 let credit = baseScore + timeScore + postScore + commentScore + fansScore; // 额外奖励:活跃用户(帖子+评论多) if (posts > 20 && comments > 100) { credit += 5; } // 官方角色额外加分:最高10分 let roleScore = 0; if (roles && roles.length > 0) { const roleScores = { admin: 10, // 管理员 "channel-owner": 5, // 频道主 agency: 5, // 交易中介 dev: 5, // 开发者 "blog-owner": 5, // 博主 detective: 5, // 侦探 active: 5, // 活跃 }; roles.forEach((role) => { const roleName = role.name?.toLowerCase(); if (roleScores[roleName]) { roleScore = Math.max(roleScore, roleScores[roleName]); } }); } credit += roleScore; // 水贴惩罚:平均每天发帖超过3个且回帖超过20条,扣10分 if (days > 0) { const avgPostsPerDay = posts / days; const avgCommentsPerDay = comments / days; if (avgPostsPerDay > 3 && avgCommentsPerDay > 20) { credit -= 10; } } // 低信誉扣60分 if (roles && roles.length > 0) { const hasBadRep = roles.some( (r) => r.name?.toLowerCase() === "bad_reputation" ); if (hasBadRep) { credit -= 60; } } return Math.max(0, Math.min(100, Math.round(credit))); }, // 根据信誉度返回颜色 getCreditColor(credit) { if (credit >= 80) return "#28a745"; // 绿色 - 高信誉 if (credit >= 60) return "#007bff"; // 蓝色 - 良好 if (credit >= 40) return "#dc3545"; // 红色 - 较低 return "#f0ad4e"; // 橙黄色 - 低信誉 }, // 获取用户信息(带重试) getUserInfo(uid, retries = 3) { return new Promise((resolve, reject) => { const tryFetch = (attempt) => { util .get(`/api/account/getInfo/${uid}`, {}, "json") .then((data) => { if (!data.success || !data.detail) { if (attempt < retries) { setTimeout(() => tryFetch(attempt + 1), 500); } else { reject("请求失败"); } return; } resolve(data.detail); }) .catch((err) => { if (attempt < retries) { setTimeout(() => tryFetch(attempt + 1), 500); } else { reject(err); } }); }; tryFetch(1); }); }, // 创建信誉度标签 createCreditTag(user, rank, credit, daysDiff) { const creditColor = this.getCreditColor(credit); const layer = layui.layer; return util.createElement( "span", { staticClass: "nsk-badge role-tag user-credit", attrs: { style: `background-color: ${creditColor}; color: white; margin-left: 3px;`, }, on: { mouseenter: function () { layer.tips( `信誉度 ${credit} 分<br>等级: Lv${rank} | 注册: ${daysDiff}天<br>帖子: ${user.nPost} | 评论: ${user.nComment}`, this, { tips: 3, time: 0 } ); }, mouseleave: function () { layer.closeAll(); }, }, }, [util.createElement("span", {}, [`信誉${credit}`])] ); }, // 为楼主添加信誉标签 async addPostAuthorCredit() { if (!unsafeWindow.__config__?.postData?.op?.uid) return; const uid = unsafeWindow.__config__.postData.op.uid; try { const user = await this.getUserInfo(uid); const daysDiff = Math.floor( (new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24) ); const rank = this.getRankByCoin(user.coin); const credit = this.calculateCredit( rank, daysDiff, user.nPost, user.nComment, user.fans || 0, user.roles || [] ); const creditTag = this.createCreditTag(user, rank, credit, daysDiff); const authorLink = document.querySelector( "#nsk-body .nsk-post .nsk-content-meta-info .author-info>a" ); if (authorLink && !authorLink.nextElementSibling?.classList?.contains("user-credit")) { authorLink.after(creditTag); } } catch (err) { console.error("获取楼主信息失败:", err); } }, // 为评论者添加信誉标签 addCommentCredits() { const comments = unsafeWindow.__config__?.postData?.comments || []; if (comments.length === 0) return; const userCache = new Map(); comments.forEach((comment) => { const uid = comment.poster?.uid; if (!uid) return; const commentEl = document.querySelector( `li[data-comment-id="${comment.commentId}"]` ); if (!commentEl) return; const authorLink = commentEl.querySelector(".author-info > a"); if ( !authorLink || authorLink.nextElementSibling?.classList?.contains("user-credit") ) return; // 使用缓存避免重复请求 if (!userCache.has(uid)) { userCache.set(uid, this.getUserInfo(uid)); } userCache .get(uid) .then((user) => { const daysDiff = Math.floor( (new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24) ); const rank = this.getRankByCoin(user.coin); const credit = this.calculateCredit( rank, daysDiff, user.nPost, user.nComment, user.fans || 0, user.roles || [] ); const creditTag = this.createCreditTag(user, rank, credit, daysDiff); authorLink.after(creditTag); }) .catch((err) => console.error(`获取用户 ${uid} 信息失败:`, err) ); }); }, // 初始化 init() { // 只在帖子详情页运行信誉评分系统 if (!/^\/post-/.test(location.pathname)) { console.log("[信誉评分系统] 非帖子详情页,跳过信誉评分功能"); return; } // 添加样式 const style = document.createElement("style"); style.textContent = ` .role-tag.user-credit { display: inline-block; padding: 1px 4px; border-radius: 2px; font-size: 10px; font-weight: normal; cursor: help; line-height: 1.3; vertical-align: middle; } /* 隐藏广告 */ .promotation-item { display: none !important; } `; document.head.appendChild(style); // 等待页面加载完成后添加标签 if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { setTimeout(() => { this.addPostAuthorCredit(); this.addCommentCredits(); }, 500); }); } else { setTimeout(() => { this.addPostAuthorCredit(); this.addCommentCredits(); }, 500); } console.log("[信誉评分系统] 已加载"); }, }; // 初始化圣诞帽(不依赖 layui) ChristmasHat.init(); // 确保 layui 加载完成后初始化信誉评分系统 if (typeof layui !== "undefined") { layui.use(function () { CreditSystem.init(); }); } else { console.error("[信誉评分系统] layui 未加载,信誉评分功能无法运行"); }})();放油猴脚本里面运行喔,效果如下:
评论 (0)