// ==UserScript==
// @name Buff自动刷新及购买
// @namespace http://tampermonkey.net/
// @version 2024-04-17
// @description 模仿手动操作,自动刷新和购买,建议使用批量购买,成功率更高,可以挂在后台,按理说也可以支持多开,自动发送报价的脚本在Github https://github.com/fruktoguo/BuffAutoTrader自取,记得给个star
// @include /https:\/\/buff\.163\.com\/goods\/(csgo|dota2|rust|h1z1|tf2|pubg|pubg_recycle|\d+)/
// @author YuoHira
// @license MIT
// @match https://buff.163.com/goods/*?from=market
// @icon https://www.google.com/s2/favicons?sz=64&domain=163.com
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function () {
'use strict';
// 获取当前页面的URL
console.log('当前物品ID ' + getItemID());
let itemName = document.querySelector('.detail-cont h1').textContent.trim();
console.log('物品名称 ' + itemName);
const singleConfig = {
等待载入延迟: GM_getValue(getItemID() + '等待载入延迟', 3000),
购买延迟: GM_getValue(getItemID() + '购买延迟', 200),
确认付款延迟: GM_getValue(getItemID() + '确认付款延迟', 1500),
售价过高刷新延迟: GM_getValue(getItemID() + '售价过高刷新延迟', 500),
最小价格: GM_getValue(getItemID() + '最小价格', -1),
};
const batchConfig = {
等待载入延迟: GM_getValue(getItemID() + '批量等待载入延迟', 1500),
购买延迟: GM_getValue(getItemID() + '批量购买延迟', 1000),
确认付款延迟: GM_getValue(getItemID() + '批量确认付款延迟', 1500),
售价过高刷新延迟: GM_getValue(getItemID() + '批量售价过高刷新延迟', 500),
最大价格: GM_getValue(getItemID() + '批量最大价格', -1),
购买数量: GM_getValue(getItemID() + '批量购买数量', 1)
};
let isChecking = false;
let isSingle = GM_getValue(getItemID() + 'buyMode', 'single') == 'single';
// 添加自定义样式
const css = `
@keyframes cuteBackground {
0% { background-color: #eeaaab; }
50% { background-color: #ffcccb; }
100% { background-color: #eeaaab; }
}
#my-custom-container {
position: fixed;
top: 40px;
left: 50px;
width: 320px;
height: auto;
background-color: #f3f3f3; /* 浅灰色 */
border: none;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
z-index: 10000;
padding: 10px;
transition: all 0.3s ease; /* 添加过渡效果 */
border-top-left-radius: 5px;
border-top-right-radius: 40px;
border-bottom-left-radius: 40px;
border-bottom-right-radius: 40px;
display: flex;
flex-direction: column;
align-items: center;
animation: cuteBackground 5s infinite;
}
.custom-tab-container button {
background-color: #ffcccb; /* 淡红色 */
border: none;
margin: 0;
width: 50%;
padding: 10px 10px;
cursor: pointer;
border-bottom: 2px solid transparent;
outline: none;
transition: all 0.3s ease; /* 添加过渡效果 */
border-radius: 5px; /* 添加圆角 */
}
.custom-tab-container button.active-tab {
background-color: #ff6f61; /* 深红色 */
border-color: #ff6f61;
box-shadow: 0 0 10px #ff6f61; /* 添加阴影 */
}
.custom-tab {
display: none;
padding-top: 10px;
}
.custom-tab.active {
display: block;
}
.custom-input {
display: block;
width: calc(80% - 120px);
margin-top: 5px;
padding: 5px;
border: 1px solid #bbb;
font-weight: bold;
border-radius: 3px;
transition: all 0.3s ease; /* 添加过渡效果 */
border-radius: 5px; /* 添加圆角 */
}
.custom-input:hover {
transform: scale(1.1); /* 添加弹性效果 */
}
.custom-label {
font-size: 14px;
font-weight: bold;
color: #333;
padding: 5px;
position: relative;
}
.control-button {
transition: transform 0.3s;
}
.control-button:hover {
transform: scaleX(1.1);
transition: transform 0.5s;
}
.control-button:active {
transform: scaleY(0.9);
transition: transform 0.2s;
}
`;
const head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
head.appendChild(style);
style.type = 'text/css';
style.appendChild(document.createTextNode(css));
// 创建一个容器来包含你的自定义窗口和按钮
const mainContainer = document.createElement('div');
mainContainer.style.position = 'fixed';
mainContainer.style.zIndex = '10000';
document.body.insertBefore(mainContainer, document.body.firstChild);
// 创建容器
const container = document.createElement('div');
container.id = 'my-custom-container';
document.body.insertBefore(container, document.body.firstChild);
// 创建选项卡按钮容器
const buttonContainer = document.createElement('div');
buttonContainer.className = 'custom-tab-container';
// 创建选项卡内容容器
const tabContainer = document.createElement('div');
tabContainer.className = 'custom-tab-content';
// 创建两个选项卡的按钮和内容
const tab1Button = document.createElement('button');
tab1Button.textContent = '单次购买';
tab1Button.onclick = function () {
setBuyMode('single');
};
tab1Button.classList.add('active-tab');
const tab1Content = document.createElement('div');
tab1Content.className = 'custom-tab active';
setupInputs(singleConfig, tab1Content);
const tab2Button = document.createElement('button');
tab2Button.textContent = '批量购买';
tab2Button.onclick = function () {
setBuyMode('batch');
};
const tab2Content = document.createElement('div');
tab2Content.className = 'custom-tab';
setupInputs(batchConfig, tab2Content);
setBuyMode(GM_getValue(getItemID() + 'buyMode', 'batch'));
// 添加按钮及其事件监听
let controlButton = document.createElement('button');
controlButton.className = 'control-button';
controlButton.textContent = GM_getValue(getItemID() + 'autoBuyEnabled', false) ? '停止自动购买' : '开始自动购买';
controlButton.style.width = '50%';
controlButton.style.height = '30px';
controlButton.style.marginTop = '10px';
controlButton.style.border = 'none';
controlButton.style.backgroundColor = '#ff6f61';
controlButton.style.borderRadius = '10px';
controlButton.addEventListener('click', () => {
toggleAutoBuy(controlButton);
});
// 组装容器
buttonContainer.appendChild(tab1Button);
buttonContainer.appendChild(tab2Button);
tabContainer.appendChild(tab1Content);
tabContainer.appendChild(tab2Content);
container.appendChild(buttonContainer);
container.appendChild(tabContainer);
container.appendChild(controlButton);
mainContainer.appendChild(container);
const button = document.createElement('button');
button.textContent = '>';
button.style.position = 'fixed';
button.style.top = '30px';
button.style.left = '15px';
button.style.width = '25px';
button.style.height = '25px';
button.style.fontWeight = 'bold';
button.style.borderRadius = '50%';
button.style.border = 'none';
button.style.backgroundColor = '#ff6f61'; /* 深红色 */
button.style.color = '#fff';
mainContainer.appendChild(button);
// 创建一个变量来跟踪页面的状态
let isCollapsed = false;
// 添加点击事件处理程序
button.addEventListener('click', function () {
if (isCollapsed) {
// 如果页面已经收起,就展开页面
container.style.display = 'block';
isCollapsed = false;
button.textContent = '>';
button.style.boxShadow = 'none'; // 移除阴影
button.style.transition = 'none'; // 移除过渡效果
} else {
// 如果页面没有收起,就收起页面
container.style.display = 'none';
isCollapsed = true;
button.textContent = '<';
button.style.boxShadow = '0 0 60px rgba(255,0,0,1)'; // 添加阴影
button.style.transition = 'all 0.3s ease'; // 添加过渡效果
}
});
const text = document.createElement('p');
text.textContent = '是否开启通知';
text.style.marginTop = '5px';
text.style.marginLeft = '5px';
container.appendChild(text);
// 创建一个开关,用来控制是否发送通知
const notificationSwitch = document.createElement('input');
notificationSwitch.type = 'checkbox';
notificationSwitch.id = 'notificationSwitch';
notificationSwitch.style.marginTop = '5px';
notificationSwitch.checked = GM_getValue(getItemID() + 'notificationSwitch', true);
notificationSwitch.addEventListener('change', function () {
GM_setValue(getItemID() + 'notificationSwitch', this.checked);
});
container.appendChild(notificationSwitch);
mainCheck();
function notify(title, body) {
// 检测是否发送
if (!GM_getValue(getItemID() + 'notificationSwitch', true)) {
return;
}
// 检查浏览器是否支持通知
if (!("Notification" in window)) {
//alert("This browser does not support system notifications");
}
// 检查用户是否已经同意接收通知
else if (Notification.permission === "granted") {
// 如果已经同意,创建一个通知
var notification = new Notification(title, {body: body});
}
// 否则,请求用户权限
else if (Notification.permission !== 'denied') {
Notification.requestPermission().then(function (permission) {
// 如果用户同意,创建一个通知
if (permission === "granted") {
var notification = new Notification(title, {body: body});
}
});
}
}
function getPriceElements() {
return document.querySelectorAll('.f_Strong');
}
// 定义一个函数来从URL中提取物品ID
function getItemID() {
const regExp = /goods\/(\d+)/;
const match = window.location.href.match(regExp);
if (match && match[1]) {
return match[1]; // 返回物品ID
} else {
return null; // 如果没有匹配到,返回null
}
}
// 定义一个函数来获取页面最小价格
function getMinPrice() {
const priceElements = getPriceElements();
let minPrice = Number.MAX_VALUE;
for (let priceIndex = 0; priceIndex < priceElements.length; priceIndex++) {
const priceText = priceElements[priceIndex].textContent.replace('¥ ', '').trim();
const price = parseFloat(priceText);
if (price < minPrice) {
minPrice = price;
}
}
return minPrice;
}
//单次购买
// 检查和刷新页面的函数
// 使用 ES6 的语法
function checkAndRefresh() {
if (!GM_getValue(getItemID() + 'autoBuyEnabled', false)) return;
isChecking = true;
const thresholdPrice = singleConfig.最小价格;
const minPrice = getMinPrice();
if (minPrice <= thresholdPrice) {
setTimeout(singleClickBuyButton, singleConfig.购买延迟);
} else {
console.log(`当前最低价格为 ${minPrice} ¥,高于阈值 ${thresholdPrice} ¥,刷新页面。`);
setTimeout(reload, singleConfig.售价过高刷新延迟);
}
}
function reload() {
if (GM_getValue(getItemID() + 'autoBuyEnabled', false)) {
location.reload();
}
}
// 点击购买按钮的函数
function singleClickBuyButton() {
var buyButtons = document.getElementsByClassName('i_Btn i_Btn_mid2 btn-buy-order'); // 使用class名称获取购买按钮
console.log("找到购买按钮数: " + buyButtons.length); // 输出找到的购买按钮数量到控制台
// 如果页面上有购买按钮
if (buyButtons[0]) {
console.log("找到购买按钮");
buyButtons[0].click(); // 点击第一个购买按钮
setTimeout(confirmPurchase, singleConfig.确认付款延迟); //
setTimeout(reload, 10000);
}
}
const maxTime = 10000;
const interval = 300;
// 确认付款的函数
function confirmPurchase() {
let timer = 0;
var intervalId = setInterval(function () {
var confirmButtons = document.getElementsByClassName('i_Btn pay-btn');
//检查所有按钮的文本,并查找包含“确认付款”的按钮
if (confirmButtons[0]) {
console.log("找到确认付款按钮");
setTimeout(function () {
confirmButtons[0].click();
}, 200);
notify(`${itemName}`, `可能抢到了 ${actualNum} 个`)
if (isSingle) {
setTimeout(reload, 2000);
} else {
setTimeout(reload, 1000 + actualNum * 500);
}
clearInterval(intervalId); // 找到按钮后清除循环
}
timer += interval;
if (timer >= maxTime) {
console.log("超时,没找到确认付款按钮");
clearInterval(intervalId);
setTimeout(reload, 2000);
}
}, interval);
}
//批量购买
function batchBuy_GetAndClickBtn() {
if (!GM_getValue(getItemID() + 'autoBuyEnabled', false)) {
return
}
console.log('开始批量购买');
isChecking = true;
var batchButton = document.getElementById('batch-buy-btn');
if (batchButton) {
console.log("找到批量购买按钮");
batchButton.click();
setTimeout(batchBuy_SetNum, 1000);
}
}
//实际购买数量
let actualNum = 0;
function batchBuy_SetNum() {
//获取最大售价输入框
var maxPrice = document.getElementById('batch-buy-max-price');
if (maxPrice) {
maxPrice.value = batchConfig.最大价格;
var event = new Event('change');
maxPrice.dispatchEvent(event);
}
var butNum = document.getElementById('batch-buy-num');
if (butNum) {
butNum.value = batchConfig.购买数量;
butNum.dispatchEvent(event);
}
//输入框的实际值赋值
setTimeout(function () {
actualNum = butNum.value;
console.log("实际购买数量: " + actualNum);
}, 1000);
//延迟
setTimeout(batchBuy_Buy, batchConfig.购买延迟);
}
function batchBuy_Buy() {
//如果开启了自动购买
if (GM_getValue(getItemID() + 'autoBuyEnabled', false)) {
console.log("开始查找购买按钮");
// 找到所有的td标签
var tds = document.querySelectorAll('td');
let buyButton;
// 遍历所有的td标签
tds.forEach(function (td, index, array) {
// 找到td标签下的a标签
var a = td.querySelector('a');
// 如果a标签存在,并且a标签的文本是"确认",并且前一个td标签的文本包含"应付总额"
if (a && a.textContent === "确认" && index > 0 && array[index - 1].textContent.includes("应付总额")) {
if (!a.classList.contains('i_Btn_disabled')) {
console.log("找到确认购买按钮");
buyButton = a;
// 结束查找
return;
}
}
});
if (buyButton) {
setTimeout(function () {
console.log(buyButton.textContent);
buyButton.click();
console.log('开始寻找确认付款按钮')
setTimeout(confirmPurchase, batchConfig.确认付款延迟);
}, 500);
}
else {
console.log("未找到确认购买按钮");
setTimeout(reload, batchConfig.售价过高刷新延迟);
}
}
}
function mainCheck() {
if (GM_getValue(getItemID() + 'buyMode', 'single') == 'single') {
setTimeout(checkAndRefresh, singleConfig.等待载入延迟);
if (GM_getValue(getItemID() + 'autoBuyEnabled', false)) {
isChecking = true;
}
// 运行检查刷新函数的循环
setInterval(() => {
if (GM_getValue(getItemID() + 'autoBuyEnabled', false) && !isChecking) {
checkAndRefresh();
}
}, 2000);
} else {
setTimeout(batchBuy_GetAndClickBtn, batchConfig.等待载入延迟);
if (GM_getValue(getItemID() + 'autoBuyEnabled', false)) {
isChecking = true;
}
// 运行检查刷新函数的循环
setInterval(() => {
if (GM_getValue(getItemID() + 'autoBuyEnabled', false) && !isChecking) {
batchBuy_GetAndClickBtn();
}
}, 2000);
}
}
// 输入框设置
function setupInputs(config, content) {
const inputs = {};
for (let key in config) {
const inputContainer = document.createElement('div');
inputContainer.style.display = 'flex';
inputContainer.style.alignItems = 'center';
const label = document.createElement('label');
label.className = 'custom-label';
label.textContent = `${key}`;
label.style.marginRight = '10px';
inputContainer.appendChild(label);
const input = document.createElement('input');
input.className = 'custom-input';
input.style.marginLeft = 'auto';
input.style.marginRight = '15px';
input.type = 'number';
input.value = config[key];
inputContainer.appendChild(input);
const unit = document.createElement('span');
unit.textContent = 'ms';
inputContainer.appendChild(unit);
// 特殊处理最小价格输入框,允许输入小数
if (key.includes('价格')) {
input.step = '0.01'; // 允许精确到分
unit.textContent = '元';
}
//数量
if (key.includes('数量')) {
unit.textContent = '个';
}
input.addEventListener('change', function () {
var newKey = (isSingle ? key : '批量' + key);
let newValue = key.includes('价格') ? parseFloat(this.value) : parseInt(this.value, 10);
GM_setValue(getItemID() + newKey, newValue);
console.log(`修改 ${key} ${newKey} 为 ${newValue}`);
// console.log(config);
config[key] = newValue;
});
inputs[key] = input;
content.appendChild(inputContainer)
}
return inputs;
}
// 设置购买模式的函数
function setBuyMode(mode) {
console.log("设置购买模式: " + mode);
GM_setValue(getItemID() + 'buyMode', mode);
toggleBuyMode(mode);
}
// 切换购买模式的函数
function toggleBuyMode(mode) {
if (mode === 'single') {
isSingle = true;
tab1Content.classList.add('active');
tab2Content.classList.remove('active');
tab1Button.classList.add('active-tab');
tab2Button.classList.remove('active-tab');
} else {
isSingle = false;
tab2Content.classList.add('active');
tab1Content.classList.remove('active');
tab2Button.classList.add('active-tab');
tab1Button.classList.remove('active-tab');
}
}
// 开启和关闭自动购买的切换功能
function toggleAutoBuy(button) {
let currentStatus = GM_getValue(getItemID() + 'autoBuyEnabled', false);
GM_setValue(getItemID() + 'autoBuyEnabled', !currentStatus);
button.textContent = currentStatus ? '开始自动购买' : '停止自动购买';
}
})();