Greasy Fork

Greasy Fork is available in English.

妖火网增强脚本Plus

让妖火再次变得伟大(手动狗头.jpg)

当前为 2024-08-20 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            妖火网增强脚本Plus
// @namespace       https://www.yaohuo.me/
// @version         0.2
// @description     让妖火再次变得伟大(手动狗头.jpg)
// @author          柠檬没有汁@27894
// @match           *://yaohuo.me/*
// @match           *://*.yaohuo.me/*
// @icon            https://yaohuo.me/css/favicon.ico
// @run-at          document-body
// @license         MIT
// @grant           none
// @noframes
// @homepage        https://www.yaohuo.me/bbs/userinfo.aspx?touserid=27894
// @supportURL      https://www.yaohuo.me/bbs/userinfo.aspx?touserid=27894
// @require         https://code.jquery.com/jquery-3.7.1.min.js
// ==/UserScript==

(async function () {
  "use strict";
  // 如果JQuery未能加载成功则直接不执行所有功能
  if (!checkJQueryLoad()) return;
  // 初始化本地设置文件(存放于localStorage,清除浏览器缓存会让设置失效)
  await initSetting();
  const customSetting = JSON.parse(localStorage.getItem("yaohuoBetterPlusSetting"));
  console.log("yaohuoBetterPlus 用户设置:", customSetting);

  // 确保在页面加载完成后再执行代码,否则jquery可能会获取不到 document 内容
  $(document).ready(() => {
    customSetting["showTopAndDownBtn"] && addTopAndDown();
    // bookViewAddUbb();

    customSetting["showChuiniuWinning"] && executeFunctionForURL("/games/chuiniu/doit.aspx", chuiniuHistory);
  });
})();

// 发帖UBB增强
function bookViewAddUbb() {
  const bookViewPageList = [
    "/bbs/book_view_add.aspx",
    "/bbs/book_view_sendmoney.aspx",
    "/bbs/book_view_addvote.aspx",
    "/bbs/book_view_addfile.aspx",
    "/bbs/book_view_mod.aspx",
    "/bbs/book_view_addURL.aspx",
  ];
  console.log(window.location.pathname);
  // if (bookViewPageList.includes(window.location.pathname))
  // let targetEle = $('.book_view_add_height');
  // console.log(targetEle);
  // let newEle = $('<div class="btBox"><div class="bt2">123</div></div>');
  // // 在目标元素后面追加新元素
  // targetEle.append(newEle);
}

// 查询吹牛发布者历史大话选项
async function chuiniuHistory() {
  const elementsWithText = $("body").find(":contains('自己挑战的只能由其它友友应战!')");
  if (elementsWithText.length > 0) return;

  // 创建胜率结果显示容器,写入提示信息
  $(
    `<p id="chuiniuWinningEle" style="background:#f0f9eb;color:gray;text-align:center;margin:0 auto;padding:0 20px;">历史记录获取中...</p>`
  ).insertBefore($(".subtitle"));

  const userinfoEle = $('a[href*="userinfo.aspx"]');
  const chuiniuQueUserId = getUrlParam("touserid", userinfoEle.attr("href")); // 发布者ID
  const chuiniuQueUserNickname = userinfoEle.text(); // 发布者昵称
  const queHistoryArr = Array.from(await getQueUserHistoryArr(chuiniuQueUserId)); // 发布者历史大话ID

  if (queHistoryArr.length > 0) {
    //  获取成功
    const queHistoryAnswers = await Promise.all(queHistoryArr.map(getChuiniuAnswer));
    const countAnswer1 = queHistoryAnswers.filter((v) => v === "1").length;
    const countAnswer2 = queHistoryAnswers.filter((v) => v === "2").length;
    $("#chuiniuWinningEle")
      .css({
        "text-align": "left",
      })
      .html(
        `“<span style="color:#3d68a8;">${chuiniuQueUserNickname}</span>”最近<span style="color:blue;font-weight:bold;">${queHistoryAnswers.length}</span>次已完成大话选项:答案<span style="color:blue;font-weight:bold;">1</span>次数:<span style="color:red;font-weight:bold;">${countAnswer1}</span>,答案<span style="color:blue;font-weight:bold;">2</span>次数: <span style="color:red;font-weight:bold;">${countAnswer2}</span>`
      );
  } else {
    // 获取失败
    $("#chuiniuWinningEle").html(`<span style="color:red;">未知错误,获取历史数据失败,请私信反馈</span>`);
  }

  // 获取指定大话答案
  async function getChuiniuAnswer(chuiniuId) {
    const chuiniuRes = await getPageContent(`/games/chuiniu/book_view.aspx?id=${chuiniuId}`);
    const ansRule1 = chuiniuRes.match(/挑战方出的是\[答案1\]/);
    const ansRule2 = chuiniuRes.match(/挑战方出的是\[答案2\]/);
    if (ansRule1) return "1";
    if (ansRule2) return "2";
  }
  // 获取对方大话指定条数历史记录ID
  async function getQueUserHistoryArr(toUserId, computeTotal = 15) {
    return new Promise(async (resolve, reject) => {
      const idArr = new Set(); // 存放大话ID,利用Set特性去重(翻页时会有重复项出现,非本脚本bug)
      let historyPage = 1; // 翻页,达到预设值时停止

      const historyText = await getPageContent(`/games/chuiniu/book_list.aspx?type=0&touserid=${toUserId}`);
      const userHistoryTotal = historyText.slice(historyText.indexOf("页,共 ") + 4, historyText.indexOf(" 条")); // 吹牛历史总条数

      const getQueUserHistoryid = async () => {
        const tempElements = $(historyText).filter(".line1, .line2");
        for (const line of tempElements) {
          const idLink = line.querySelector('a[href*="book_view.aspx"]');
          if (idLink && !line.textContent.includes("进行中")) {
            const dahuaId = getUrlParam("id", idLink.href);
            if (dahuaId) idArr.add(dahuaId);
            if (idArr.length >= computeTotal) break;
          }
        }
        if (idArr.length < 15 && userHistoryTotal > 15) {
          historyPage++;
          getQueUserHistoryid();
        } else {
          resolve(idArr);
        }
      };
      getQueUserHistoryid();
    });
  }
}

// 一键回到顶部/底部,在原作者基础上做了删减、改动,原作者发布地址:http://greasyfork.icu/zh-CN/scripts/38899-回到顶部-底部
function addTopAndDown() {
  if (window.self != window.top) return;
  function ce(n) {
    return document.createElement(n);
  }

  function addStyle(css) {
    let head = document.head || document.getElementsByTagName("head")[0];
    if (head) {
      let style = ce("style");
      style.type = "text/css";
      style.appendChild(document.createTextNode(css));
      head.appendChild(style);
    }
  }

  let el =
      navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("MSIE") != -1
        ? document.documentElement
        : document.body,
    t1,
    t2,
    speed_by_click = 200,
    zIindex = 1001;

  function getDocumentHeight() {
    return document.body.scrollHeight > document.body.offsetHeight
      ? document.body.scrollHeight
      : document.body.offsetHeight;
  }
  function get_scroll(a) {
    let d = document,
      b = d.body,
      e = d.documentElement,
      c = "client" + a,
      f = "scroll" + a;
    return /CSS/.test(d.compatMode) ? e[c] < e[f] : b[c] < b[f];
  }
  function scrollTo(element, to, duration) {
    (start = document.documentElement.scrollTop || document.body.scrollTop),
      (change = to - start),
      (currentTime = 0),
      (increment = 20),
      (newDuration = typeof duration === "undefined" ? 500 : duration);

    let animateScroll = function () {
      currentTime += increment;
      let val = Math.easeInOutQuad(currentTime, start, change, newDuration);
      window.scrollTo(0, val);
      if (currentTime < newDuration) {
        setTimeout(animateScroll, increment);
      }
    };
    animateScroll();
  }

  Math.easeInOutQuad = function (t, b, c, d) {
    t /= d / 2;
    if (t < 1) return (c / 2) * t * t + b;
    t--;
    return (-c / 2) * (t * (t - 2) - 1) + b;
  };

  function shareCSS() {
    let s = "",
      img_up,
      img_dn;

    img_up =
      "data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAUCAYAAACAl21KAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB+SURBVDhPY1i1atV/amAGahgCMoNhaIGlS5cKAp19BoRBbLJcj2QILDJINwzoAmMgfoclIkBixkS5DI8hMJcRNgxoSBoOl6CnNZBhaVhdBjWE1MSJahjQkA4KEmYH2GUrV66cSYEhYB+AzKBtFiHkQqKiH6Ro1CDCQTWgYQQAs81DU0G/83sAAAAASUVORK5CYII=";
    img_dn =
      "data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAUCAYAAACAl21KAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACPSURBVDhPY2DAAlatWvUfH8amB6vYqEGEg2pgw4iQ7cTKM6xcuXImsYpxqQOZAQ4woIIOCgzrQAl1oEFpZBiWhitFgwx7R4SBIDXYDYGZDFRgTMAwkCHGhBMRJMxwGUa8ITCbli5dKgg08AySN8+AxIhyCboiJMPIN4Qsm6miiYioxltawvSDYogohYTUAQC80UNTOht/YwAAAABJRU5ErkJggg==";
    s +=
      "#play_btn_up { position:fixed; right:0; top:55%;z-index:" +
      zIindex +
      "; height:40px; width:36px; cursor:pointer; background:url(" +
      img_up +
      ") no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); border-radius:5px 0 0 5px; margin-top:-24px; }";
    s +=
      "#play_btn_dn { position:fixed; right:0; top:60%;   z-index:" +
      zIindex +
      "; height:40px; width:36px; cursor:pointer; background:url(" +
      img_dn +
      ") no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); border-radius:5px 0 0 5px; margin-top:-24px; }";

    s +=
      ".play_btn { -webkit-transition-duration:0.5s linear; -o-transition-duration:0.5s linear; -moz-transition-duration:0.5s linear; transition-duration:0.5s linear; opacity:0.65; }";
    s += ".play_btn:hover { opacity:1; }";

    addStyle("" + s);
  }

  function create_btn_element() {
    let up,
      dn,
      scrolled,
      h = get_scroll("Height");
    if (!h) {
      return;
    }
    shareCSS();

    if (el) {
      up = ce("span");
      dn = ce("span");
      up.setAttribute("id", "play_btn_up");
      dn.setAttribute("id", "play_btn_dn");
      up.className = "play_btn";
      dn.className = "play_btn";
      document.body.appendChild(up);
      document.body.appendChild(dn);

      scrolled = window.pageYOffset || document.documentElement.scrollTop;
      up.style.display = scrolled > 0 ? "" : "none";

      up.addEventListener(
        "mouseout",
        function () {
          clearTimeout(t1);
        },
        false
      );
      dn.addEventListener(
        "mouseout",
        function () {
          clearTimeout(t2);
        },
        false
      );
      up.addEventListener(
        "click",
        function () {
          scrollTo(el, 0, speed_by_click);
        },
        false
      );
      dn.addEventListener(
        "click",
        function () {
          scrollTo(el, getDocumentHeight(), speed_by_click);
        },
        false
      );

      window.onscroll = function () {
        let scrolled = document.documentElement.scrollTop,
          diffHeight = document.body.scrollHeight - window.innerHeight;
        up.style.display = scrolled > 0 ? "" : "none";
        dn.style.display = diffHeight > scrolled ? "" : "none";
      };
    }
  }

  create_btn_element();
}

// 初始化脚本设置
function initSetting() {
  return new Promise((resolve, reject) => {
    defaultSetting = {
      // 第一次加载脚本
      firstLoadScript: true,
      // 显示设置 logo
      showSettingIcon: true,
      // 设置 logo 大小
      settingIconSize: 50,
      // 显示吹牛胜率
      showChuiniuWinning: true,
      // 显示一键回到顶部/底部
      showTopAndDownBtn: true,
      // 发帖 ubb 展开
      showMoreUbb: true,
      // 显示勋章
      showMedal: true,
      // 回帖 ubb 展开
      // 回帖表情展开
      // 回帖 +1
      // 站内图片增强
      // 一键吃肉
      oneClickCollectMoney: true,
    };
    const localSetting = JSON.parse(localStorage.getItem("yaohuoBetterPlusSetting")) || {};
    const saveSetting = { ...defaultSetting, ...localSetting }; // 合并设置,自定义项覆盖默认选项,避免添加新功能时已缓存设置没有新功能相关从而产生bug
    try {
      localStorage.setItem("yaohuoBetterPlusSetting", JSON.stringify(saveSetting));
      console.log("======> [ 已成功初始化设置 ]");
      resolve();
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 递归、检测jQuery是否成功加载
 * @param {Number} attempt  已检测次数
 * @param {Number} maxAttempts 最大检测次数
 * @param {Number} interval 检测间隔时间/ms
 * @returns
 */
function checkJQueryLoad(attempt = 0, maxAttempts = 50, interval = 200) {
  if (typeof jQuery !== "undefined") {
    console.log("已成功加载 jQuery");
    return true;
  } else if (attempt < maxAttempts) {
    console.log("已检测次数:", attempt + 1);
    setTimeout(() => {
      checkJQueryLoad(attempt + 1, maxAttempts, interval);
    }, interval);
  } else {
    console.log("无法加载 jQuery");
    notifyBox("jQuery 加载失败,增强脚本运行已终止", false);
    return false;
  }
}

/* <=== 自定义方法开始 ===> */

// 当前页面为指定 url 时执行函数
function executeFunctionForURL(targetPath, executeFunction) {
  if (typeof targetPath !== "string" || typeof executeFunction !== "function") {
    throw new Error("参数无效!");
  }
  window.location.pathname === targetPath && executeFunction();
}

// 从指定url获取get参数`
function getUrlParam(paramName, targetUrl = window.location.href) {
  try {
    let urlObj = new URL(targetUrl, window.location.origin);
    return urlObj.searchParams.get(paramName);
  } catch (error) {
    console.error("无效的URL:", targetUrl, error);
    return null;
  }
}
// 获取指定页面内容
function getPageContent(path, method = "GET") {
  const url = `${window.location.origin}${path}`;
  return new Promise((resolve, reject) => {
    $.ajax({
      url,
      method,
      dataType: "html",
      success: (response) => {
        resolve(response);
      },
      error: (error) => {
        reject(error);
      },
    });
  });
}

// 设置保存
function settingChange(setName, setValue) {
  let cacheSetting = JSON.parse(localStorage.getItem("yaohuoBetterPlusSetting"));
  cacheSetting[setName] = setValue;
  try {
    localStorage.setItem("yaohuoBetterPlusSetting", JSON.stringify(cacheSetting));
    notifyBox("保存成功");
  } catch (error) {
    notifyBox("保存失败", false);
  }
}
// 设置获取
function settingGet(name) {
  // let cacheSetting = JSON.parse(localStorage.getItem("yaohuoBetterPlusSetting"));
  // return cacheSetting[name];
  try {
    return JSON.parse(localStorage.getItem("yaohuoBetterPlusSetting"))[name];
  } catch (error) {
    throw new Error("未知错误,获取设置失败");
  }
}

/**
 * 弹出提示
 * @param {String} message 提示内容
 * @param {Boolean} status 提示状态,true成功,false失败,默认true
 * @param {Number} delayTime 提示时间/ms,默认1500ms
 */
let offsetY = 0; // 消息框初始垂直偏移量
function notifyBox(message, status = true, delayTime = 1500) {
  // 消息父容器
  const containerDiv = $("<div>")
    .css({
      position: "fixed",
      top: `calc(100px + ${offsetY}px)`,
      left: "50%",
      transform: "translateX(-50%)",
      maxWidth: "80%",
      width: "auto",
      textAlign: "center",
    })
    .appendTo("body");
  // 消息框创建
  const messageDiv = $("<div>")
    .text(message)
    .css({
      background: status ? "#f0f9eb" : "#fef0f0",
      color: status ? "#67c23a" : "#f56c6c",
      padding: "5px 20px",
      boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
      whiteSpace: "normal",
      wordWrap: "break-word",
      overflowWrap: "break-word",
      hyphens: "auto",
      borderRadius: "5px",
      maxWidth: "100%", // 设置消息框的最大宽度
    })
    .appendTo(containerDiv);
  // 延迟后消息框销毁
  messageDiv
    .fadeIn()
    .delay(delayTime)
    .fadeOut(function () {
      containerDiv.remove();
      offsetY -= 50; // 删除后减少50px的垂直偏移量
    });

  offsetY += 50; // 增加消息框的高度和间距
}

/* <=== 自定义方法结束 ===> */