// ==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 未加载,信誉评分功能无法运行");  }})();

放油猴脚本里面运行喔,效果如下: