// ==UserScript==
// @name 斗鱼鱼塘商城兑换工具
// @namespace YourNamespaceHere
// @version 1.3
// @description 斗鱼鱼塘商城自动兑换工具 (注意手动设置个人用户ID以及房间号)
// @match https://www.douyu.com/pages/fish-act/mine*
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// ---------- 重要 ----------//
let previousAcfCcnValue = null;
let ctnid = '123'; ///用户ID 在发送请求的时候会自动在Cookies获取最新的ID
const roomid = '123'; //房间ID 不支持靓号 (某些奖品需要粉丝牌等级才能兑)
// 用于判断页面是否加载完成的标志变量
let pageLoaded = false;
// 监听页面加载状态改变事件
window.addEventListener('load', function () {
pageLoaded = true;
initScript();
});
// 初始化脚本的函数,在页面加载完成后执行具体操作
function initScript() {
// 添加悬浮窗样式
GM_addStyle(`
#overlay {
position: fixed;
top: 26%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, 0.9);
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
display: none;
z-index: 9999;
}
button {
margin: 5px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
}
button.controlExchange {
background-color: red;
color: white;
margin: 5px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
}
button.autoExchange {
background-color: red;
color: white;
margin: 5px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 5px;
}
select {
margin: 5px;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 5px;
}
`);
// 创建悬浮窗元素及按钮
const overlay = document.createElement('div');
overlay.id = 'overlay';
// 创建控制兑换的按钮(集成启动和停止功能)
const controlExchangeButton = document.createElement('button');
controlExchangeButton.textContent = '启动兑换 ✔';
controlExchangeButton.className = 'controlExchange';
// 创建自动兑换按钮
const autoExchangeButton = document.createElement('button');
autoExchangeButton.textContent = '自动兑换 ✖';
autoExchangeButton.className = 'autoExchange';
// 创建下拉菜单元素
const selectMenu = document.createElement('select');
// 我只换了每种类型的第一个 再根据斗鱼的尿性推算的后面几个数字
const items = [
{ value: 'hahahahha', text: '请选择需要兑换的奖品' },
{ value: 'PROP_1', text: '3级粉丝牌 初级水手' },
{ value: 'PROP_2', text: '3级粉丝牌 精英士官' },
{ value: 'PROP_3', text: '6级粉丝牌 心动卡' },
{ value: 'FREE_PROP_1', text: '10 陪伴印章' },
{ value: 'FREE_PROP_2', text: '30 陪伴印章' },
{ value: 'FREE_PROP_3', text: '50 陪伴印章' },
{ value: 'YC_TY_1', text: '0.1 鱼翅' },
{ value: 'YC_TY_2', text: '0.5 鱼翅' },
{ value: 'YC_TY_3', text: '1 鱼翅' },
{ value: 'YW_1', text: '100 鱼丸' },
{ value: 'YW_2', text: '200 鱼丸' },
{ value: 'YW_3', text: '500 鱼丸' },
{ value: 'YC_CHIP_1', text: '2 鱼翅碎片' },
{ value: 'YC_CHIP_2', text: '5 鱼翅碎片' }
];
// 循环创建下拉菜单选项
items.forEach(item => {
const option = document.createElement('option');
option.value = item.value;
option.textContent = item.text;
selectMenu.appendChild(option);
});
overlay.appendChild(controlExchangeButton);
overlay.appendChild(autoExchangeButton);
overlay.appendChild(selectMenu);
document.body.appendChild(overlay);
// 用于记录鼠标按下时的坐标以及悬浮窗初始坐标
let startX, startY, offsetX, offsetY;
// 为悬浮窗添加鼠标按下事件监听器
overlay.addEventListener('mousedown', function (e) {
startX = e.pageX;
startY = e.pageY;
offsetX = overlay.offsetLeft;
offsetY = overlay.offsetTop;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
});
// 拖动时的处理函数
function drag(e) {
overlay.style.left = offsetX + e.pageX - startX + 'px';
overlay.style.top = offsetY + e.pageY - startY + 'px';
}
// 停止拖动的处理函数
function stopDrag() {
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
// 用于存储当前选择的index值的变量 默认无 避免出Bug的时候花光光
let selectedIndexValue = 'hahahahha';
// 监听下拉菜单选项改变事件,更新选中的index值
selectMenu.addEventListener('change', function () {
selectedIndexValue = this.value;
console.log(`目前选择 ${this.options[this.selectedIndex].textContent} - ${this.value}`); //检查切换功能
});
// 用于控制兑换代码是否执行的标志变量,初始设为false表示未运行
let isRunning = false;
// 用于标记自动兑换功能是否开启,初始设为false
let autoExchangeEnabled = false;
// 显示悬浮窗
function showOverlay() {
overlay.style.display = 'block';
}
// 隐藏悬浮窗
function hideOverlay() {
overlay.style.display = 'none';
}
// // 点击启动按钮的处理函数
// startButton.addEventListener('click', function () {
// isRunning = true;
// runExchangeLoop();
// });
// // 点击停止按钮的处理函数
// stopButton.addEventListener('click', function () {
// isRunning = false;
// });
// 点击控制兑换按钮的处理函数
controlExchangeButton.addEventListener('click', function () {
if (isRunning) {
isRunning = false;
this.textContent = '启动兑换 ✔';
this.style.backgroundColor ='red';
console.log(`停止兑换 ${isRunning}`);
} else {
isRunning = true;
this.textContent = '停止兑换 ✖';
this.style.backgroundColor = 'green';
console.log(`开始兑换 ${isRunning}`);
runExchangeLoop();
}
});
// 点击自动兑换按钮的处理函数
autoExchangeButton.addEventListener('click', function () {
autoExchangeEnabled =!autoExchangeEnabled;
if (autoExchangeEnabled) {
this.textContent = '自动兑换中 ✔';
this.style.backgroundColor = 'green';
startAutoExchange();
} else {
this.textContent = '自动兑换 ✖';
this.style.backgroundColor = 'red';
stopAutoExchange();
}
});
// 获取当前时间的分钟和秒数
function getCurrentTime() {
const now = new Date();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
return { minutes, seconds };
}
// 模拟兑换代码执行的函数(这里简化了之前的fetch请求,实际要替换成完整准确的)
async function exchange() {
try {
const cookies = document.cookie;
const acf_ccn = cookies.split('; ').find(cookie => cookie.startsWith('acf_ccn='));
if (acf_ccn) {
let acf_ccnValue = acf_ccn.split('=')[1];
if (previousAcfCcnValue!== acf_ccnValue) {
console.log(`CtnID 已经刷新 \n 旧ID:${ctnid} \n 新ID:${acf_ccnValue}`);
previousAcfCcnValue = acf_ccnValue;
ctnid = acf_ccnValue;
}
}
console.log(`兑换请求属性设置 ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`);
await fetch("https://www.douyu.com/japi/revenuenc/web/actfans/convert/convertOpt", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
"content-type": "application/x-www-form-urlencoded",
"priority": "u=1, i",
"sec-ch-ua": "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin"
},
"referrer": "https://www.douyu.com/pages/fish-act/shop",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`,
"method": "POST",
"mode": "cors",
"credentials": "include"
});
// await GM_xmlhttpRequest({
// method: 'POST',
// url: "https://www.douyu.com/japi/revenuenc/web/actfans/convert/convertOpt",
// headers: {
// "accept": "application/json, text/plain, */*",
// "accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
// "content-type": "application/x-www-form-urlencoded",
// "priority": "u=1, i",
// "sec-ch-ua": "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
// "sec-ch-ua-mobile": "?0",
// "sec-ch-ua-platform": "\"Windows\"",
// "sec-fetch-dest": "empty",
// "sec-fetch-mode": "cors",
// "sec-fetch-site": "same-origin"
// },
// referrer: "https://www.douyu.com/pages/fish-act/shop",
// referrerPolicy: "strict-origin-when-cross-origin",
// data: `ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`,
// onload: function (response) {
// console.log('兑换请求响应:', response);
// },
// onerror: function (error) {
// console.error('兑换出现错误:', error);
// }
// });
} catch (error) {
console.error('兑换出现错误:', error);
}
await sleep(100); //0.1 秒运行一次 避免CPU占用过高崩溃
}
// 循环执行兑换代码的函数(根据标志变量控制)
async function runExchangeLoop() {
let count = 1;
let targetCount = 200 //0,1秒运行一次 10次=1秒 100次=10秒 默认200次= 20秒 建议在 59分50秒点击启动, 会在大约00分10~13秒结束
while (isRunning) {
await exchange();
console.log(`目前兑换请求发送次数 ${count}`);
count++;
updateControlExchangeButton(isRunning,targetCount-count);
if (count-1 >= targetCount) {
isRunning = false;
updateControlExchangeButton(isRunning,targetCount-count);
}
}
}
// 独立的自动兑换循环执行函数
async function autoExchangeLoop() {
console.log('启动自动兑换功能');
let autoExchangeCount = 0;
while (autoExchangeEnabled) {
const currentTime = getCurrentTime();
if (isInTimeRange()) {
autoExchangeCount = 0;
console.log(`目前时间 ${currentTime.minutes}分${currentTime.seconds}秒 发送兑换请求`);
await exchange();
console.log(`目前时间 ${currentTime.minutes}分${currentTime.seconds}秒 发送兑换请求结束`);
} else {
await sleep(1000); // 不在时间区间内,等待1秒后再次检查时间
autoExchangeCount++;
if(autoExchangeCount % 60 === 0){
console.log(`自动兑换运行中 每分钟提示一次 ${autoExchangeCount/60} 目前时间 ${currentTime.minutes}分${currentTime.seconds}秒`);
}
}
}
}
// 启动自动兑换循环
function startAutoExchange() {
autoExchangeLoop();
console.log(`开始自动兑换${autoExchangeEnabled}`);
}
// 停止自动兑换循环
function stopAutoExchange() {
autoExchangeEnabled = false;
console.log(`停止自动兑换${autoExchangeEnabled}`);
}
// 判断当前时间是否在指定时间区间内(59分58秒 - 00分05秒)
function isInTimeRange() {
const currentTime = getCurrentTime();
return (currentTime.minutes === 59 && currentTime.seconds >= 58) || (currentTime.minutes === 0 && currentTime.seconds <= 5);
}
// 简单的异步等待函数(以毫秒为单位)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function updateControlExchangeButton(isRunning,countLeft) {
if (isRunning) {
controlExchangeButton.textContent = `停止兑换 ✖ 剩余请求 ${countLeft}`;
controlExchangeButton.style.backgroundColor = 'green';
} else {
controlExchangeButton.textContent = '启动兑换 ✔';
controlExchangeButton.style.backgroundColor ='red';
}
}
// 页面加载完成后显示悬浮窗
showOverlay();
}
})();