// ==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();
});
}
}
// 一键回到顶部/底部,在原作者基础上做了删减、改动,原作者发布地址:https://greasyfork.org/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; // 增加消息框的高度和间距
}
/* <=== 自定义方法结束 ===> */