斗鱼鱼塘商城兑换工具

斗鱼鱼塘商城自动兑换工具 (注意手动设置个人用户ID以及房间号)

Εγκατάσταση αυτού του κώδικαΒοήθεια
Κώδικας προτεινόμενος από τον δημιιουργό

Μπορεί, επίσης, να σας αρέσει ο κώδικας 斗鱼钓鱼自动操作脚本.

Εγκατάσταση αυτού του κώδικα
  1. // ==UserScript==
  2. // @name 斗鱼鱼塘商城兑换工具
  3. // @namespace YourNamespaceHere
  4. // @version 1.3
  5. // @description 斗鱼鱼塘商城自动兑换工具 (注意手动设置个人用户ID以及房间号)
  6. // @match https://www.douyu.com/pages/fish-act/mine*
  7. // @grant GM_addStyle
  8. // @grant GM_xmlhttpRequest
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // ---------- 重要 ----------//
  15. let previousAcfCcnValue = null;
  16. let ctnid = '123'; ///用户ID 在发送请求的时候会自动在Cookies获取最新的ID
  17. const roomid = '123'; //房间ID 不支持靓号 (某些奖品需要粉丝牌等级才能兑)
  18.  
  19. // 用于判断页面是否加载完成的标志变量
  20. let pageLoaded = false;
  21.  
  22. // 监听页面加载状态改变事件
  23. window.addEventListener('load', function () {
  24. pageLoaded = true;
  25. initScript();
  26. });
  27.  
  28. // 初始化脚本的函数,在页面加载完成后执行具体操作
  29. function initScript() {
  30. // 添加悬浮窗样式
  31. GM_addStyle(`
  32. #overlay {
  33. position: fixed;
  34. top: 26%;
  35. left: 50%;
  36. transform: translate(-50%, -50%);
  37. background-color: rgba(255, 255, 255, 0.9);
  38. padding: 20px;
  39. border-radius: 10px;
  40. box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  41. display: none;
  42. z-index: 9999;
  43. }
  44.  
  45. button {
  46. margin: 5px;
  47. padding: 10px 20px;
  48. font-size: 16px;
  49. cursor: pointer;
  50. border: none;
  51. border-radius: 5px;
  52. }
  53.  
  54. button.controlExchange {
  55. background-color: red;
  56. color: white;
  57. margin: 5px;
  58. padding: 10px 20px;
  59. font-size: 16px;
  60. cursor: pointer;
  61. border: none;
  62. border-radius: 5px;
  63. }
  64.  
  65. button.autoExchange {
  66. background-color: red;
  67. color: white;
  68. margin: 5px;
  69. padding: 10px 20px;
  70. font-size: 16px;
  71. cursor: pointer;
  72. border: none;
  73. border-radius: 5px;
  74. }
  75.  
  76. select {
  77. margin: 5px;
  78. padding: 10px;
  79. font-size: 16px;
  80. border: 1px solid #ccc;
  81. border-radius: 5px;
  82. }
  83. `);
  84.  
  85. // 创建悬浮窗元素及按钮
  86. const overlay = document.createElement('div');
  87. overlay.id = 'overlay';
  88.  
  89. // 创建控制兑换的按钮(集成启动和停止功能)
  90. const controlExchangeButton = document.createElement('button');
  91. controlExchangeButton.textContent = '启动兑换 ✔';
  92. controlExchangeButton.className = 'controlExchange';
  93.  
  94.  
  95. // 创建自动兑换按钮
  96. const autoExchangeButton = document.createElement('button');
  97. autoExchangeButton.textContent = '自动兑换 ✖';
  98. autoExchangeButton.className = 'autoExchange';
  99.  
  100. // 创建下拉菜单元素
  101. const selectMenu = document.createElement('select');
  102.  
  103. // 我只换了每种类型的第一个 再根据斗鱼的尿性推算的后面几个数字
  104. const items = [
  105. { value: 'hahahahha', text: '请选择需要兑换的奖品' },
  106. { value: 'PROP_1', text: '3级粉丝牌 初级水手' },
  107. { value: 'PROP_2', text: '3级粉丝牌 精英士官' },
  108. { value: 'PROP_3', text: '6级粉丝牌 心动卡' },
  109. { value: 'FREE_PROP_1', text: '10 陪伴印章' },
  110. { value: 'FREE_PROP_2', text: '30 陪伴印章' },
  111. { value: 'FREE_PROP_3', text: '50 陪伴印章' },
  112. { value: 'YC_TY_1', text: '0.1 鱼翅' },
  113. { value: 'YC_TY_2', text: '0.5 鱼翅' },
  114. { value: 'YC_TY_3', text: '1 鱼翅' },
  115. { value: 'YW_1', text: '100 鱼丸' },
  116. { value: 'YW_2', text: '200 鱼丸' },
  117. { value: 'YW_3', text: '500 鱼丸' },
  118. { value: 'YC_CHIP_1', text: '2 鱼翅碎片' },
  119. { value: 'YC_CHIP_2', text: '5 鱼翅碎片' }
  120. ];
  121.  
  122. // 循环创建下拉菜单选项
  123. items.forEach(item => {
  124. const option = document.createElement('option');
  125. option.value = item.value;
  126. option.textContent = item.text;
  127. selectMenu.appendChild(option);
  128. });
  129.  
  130. overlay.appendChild(controlExchangeButton);
  131. overlay.appendChild(autoExchangeButton);
  132. overlay.appendChild(selectMenu);
  133. document.body.appendChild(overlay);
  134.  
  135. // 用于记录鼠标按下时的坐标以及悬浮窗初始坐标
  136. let startX, startY, offsetX, offsetY;
  137.  
  138. // 为悬浮窗添加鼠标按下事件监听器
  139. overlay.addEventListener('mousedown', function (e) {
  140. startX = e.pageX;
  141. startY = e.pageY;
  142. offsetX = overlay.offsetLeft;
  143. offsetY = overlay.offsetTop;
  144. document.addEventListener('mousemove', drag);
  145. document.addEventListener('mouseup', stopDrag);
  146. });
  147.  
  148. // 拖动时的处理函数
  149. function drag(e) {
  150. overlay.style.left = offsetX + e.pageX - startX + 'px';
  151. overlay.style.top = offsetY + e.pageY - startY + 'px';
  152. }
  153.  
  154. // 停止拖动的处理函数
  155. function stopDrag() {
  156. document.removeEventListener('mousemove', drag);
  157. document.removeEventListener('mouseup', stopDrag);
  158. }
  159.  
  160. // 用于存储当前选择的index值的变量 默认无 避免出Bug的时候花光光
  161. let selectedIndexValue = 'hahahahha';
  162.  
  163. // 监听下拉菜单选项改变事件,更新选中的index值
  164. selectMenu.addEventListener('change', function () {
  165. selectedIndexValue = this.value;
  166. console.log(`目前选择 ${this.options[this.selectedIndex].textContent} - ${this.value}`); //检查切换功能
  167. });
  168.  
  169. // 用于控制兑换代码是否执行的标志变量,初始设为false表示未运行
  170. let isRunning = false;
  171.  
  172. // 用于标记自动兑换功能是否开启,初始设为false
  173. let autoExchangeEnabled = false;
  174.  
  175. // 显示悬浮窗
  176. function showOverlay() {
  177. overlay.style.display = 'block';
  178. }
  179.  
  180. // 隐藏悬浮窗
  181. function hideOverlay() {
  182. overlay.style.display = 'none';
  183. }
  184.  
  185. // // 点击启动按钮的处理函数
  186. // startButton.addEventListener('click', function () {
  187. // isRunning = true;
  188. // runExchangeLoop();
  189. // });
  190.  
  191. // // 点击停止按钮的处理函数
  192. // stopButton.addEventListener('click', function () {
  193. // isRunning = false;
  194. // });
  195.  
  196. // 点击控制兑换按钮的处理函数
  197. controlExchangeButton.addEventListener('click', function () {
  198. if (isRunning) {
  199. isRunning = false;
  200. this.textContent = '启动兑换 ✔';
  201. this.style.backgroundColor ='red';
  202. console.log(`停止兑换 ${isRunning}`);
  203. } else {
  204. isRunning = true;
  205. this.textContent = '停止兑换 ✖';
  206. this.style.backgroundColor = 'green';
  207. console.log(`开始兑换 ${isRunning}`);
  208. runExchangeLoop();
  209. }
  210. });
  211.  
  212. // 点击自动兑换按钮的处理函数
  213. autoExchangeButton.addEventListener('click', function () {
  214. autoExchangeEnabled =!autoExchangeEnabled;
  215. if (autoExchangeEnabled) {
  216. this.textContent = '自动兑换中 ✔';
  217. this.style.backgroundColor = 'green';
  218. startAutoExchange();
  219. } else {
  220. this.textContent = '自动兑换 ✖';
  221. this.style.backgroundColor = 'red';
  222. stopAutoExchange();
  223. }
  224. });
  225.  
  226. // 获取当前时间的分钟和秒数
  227. function getCurrentTime() {
  228. const now = new Date();
  229. const minutes = now.getMinutes();
  230. const seconds = now.getSeconds();
  231. return { minutes, seconds };
  232. }
  233.  
  234. // 模拟兑换代码执行的函数(这里简化了之前的fetch请求,实际要替换成完整准确的)
  235. async function exchange() {
  236. try {
  237. const cookies = document.cookie;
  238. const acf_ccn = cookies.split('; ').find(cookie => cookie.startsWith('acf_ccn='));
  239. if (acf_ccn) {
  240. let acf_ccnValue = acf_ccn.split('=')[1];
  241. if (previousAcfCcnValue!== acf_ccnValue) {
  242. console.log(`CtnID 已经刷新 \n ID:${ctnid} \n ID:${acf_ccnValue}`);
  243. previousAcfCcnValue = acf_ccnValue;
  244. ctnid = acf_ccnValue;
  245. }
  246. }
  247. console.log(`兑换请求属性设置 ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`);
  248. await fetch("https://www.douyu.com/japi/revenuenc/web/actfans/convert/convertOpt", {
  249. "headers": {
  250. "accept": "application/json, text/plain, */*",
  251. "accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
  252. "content-type": "application/x-www-form-urlencoded",
  253. "priority": "u=1, i",
  254. "sec-ch-ua": "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
  255. "sec-ch-ua-mobile": "?0",
  256. "sec-ch-ua-platform": "\"Windows\"",
  257. "sec-fetch-dest": "empty",
  258. "sec-fetch-mode": "cors",
  259. "sec-fetch-site": "same-origin"
  260. },
  261. "referrer": "https://www.douyu.com/pages/fish-act/shop",
  262. "referrerPolicy": "strict-origin-when-cross-origin",
  263. "body": `ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`,
  264. "method": "POST",
  265. "mode": "cors",
  266. "credentials": "include"
  267. });
  268. // await GM_xmlhttpRequest({
  269. // method: 'POST',
  270. // url: "https://www.douyu.com/japi/revenuenc/web/actfans/convert/convertOpt",
  271. // headers: {
  272. // "accept": "application/json, text/plain, */*",
  273. // "accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
  274. // "content-type": "application/x-www-form-urlencoded",
  275. // "priority": "u=1, i",
  276. // "sec-ch-ua": "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
  277. // "sec-ch-ua-mobile": "?0",
  278. // "sec-ch-ua-platform": "\"Windows\"",
  279. // "sec-fetch-dest": "empty",
  280. // "sec-fetch-mode": "cors",
  281. // "sec-fetch-site": "same-origin"
  282. // },
  283. // referrer: "https://www.douyu.com/pages/fish-act/shop",
  284. // referrerPolicy: "strict-origin-when-cross-origin",
  285. // data: `ctn=${ctnid}&rid=${roomid}&index=${selectedIndexValue}`,
  286. // onload: function (response) {
  287. // console.log('兑换请求响应:', response);
  288. // },
  289. // onerror: function (error) {
  290. // console.error('兑换出现错误:', error);
  291. // }
  292. // });
  293. } catch (error) {
  294. console.error('兑换出现错误:', error);
  295. }
  296. await sleep(100); //0.1 秒运行一次 避免CPU占用过高崩溃
  297. }
  298.  
  299. // 循环执行兑换代码的函数(根据标志变量控制)
  300. async function runExchangeLoop() {
  301. let count = 1;
  302. let targetCount = 200 //0,1秒运行一次 10次=1秒 100次=10秒 默认200次= 20秒 建议在 59分50秒点击启动, 会在大约00分10~13秒结束
  303. while (isRunning) {
  304. await exchange();
  305. console.log(`目前兑换请求发送次数 ${count}`);
  306. count++;
  307. updateControlExchangeButton(isRunning,targetCount-count);
  308. if (count-1 >= targetCount) {
  309. isRunning = false;
  310. updateControlExchangeButton(isRunning,targetCount-count);
  311. }
  312. }
  313. }
  314.  
  315. // 独立的自动兑换循环执行函数
  316. async function autoExchangeLoop() {
  317. console.log('启动自动兑换功能');
  318. let autoExchangeCount = 0;
  319. while (autoExchangeEnabled) {
  320. const currentTime = getCurrentTime();
  321. if (isInTimeRange()) {
  322. autoExchangeCount = 0;
  323. console.log(`目前时间 ${currentTime.minutes}分${currentTime.seconds}秒 发送兑换请求`);
  324. await exchange();
  325. console.log(`目前时间 ${currentTime.minutes}分${currentTime.seconds}秒 发送兑换请求结束`);
  326. } else {
  327. await sleep(1000); // 不在时间区间内,等待1秒后再次检查时间
  328. autoExchangeCount++;
  329. if(autoExchangeCount % 60 === 0){
  330. console.log(`自动兑换运行中 每分钟提示一次 ${autoExchangeCount/60} 目前时间 ${currentTime.minutes}分${currentTime.seconds}秒`);
  331. }
  332. }
  333. }
  334. }
  335.  
  336. // 启动自动兑换循环
  337. function startAutoExchange() {
  338. autoExchangeLoop();
  339. console.log(`开始自动兑换${autoExchangeEnabled}`);
  340. }
  341.  
  342. // 停止自动兑换循环
  343. function stopAutoExchange() {
  344. autoExchangeEnabled = false;
  345. console.log(`停止自动兑换${autoExchangeEnabled}`);
  346. }
  347.  
  348. // 判断当前时间是否在指定时间区间内(59分58秒 - 00分05秒)
  349. function isInTimeRange() {
  350. const currentTime = getCurrentTime();
  351. return (currentTime.minutes === 59 && currentTime.seconds >= 58) || (currentTime.minutes === 0 && currentTime.seconds <= 5);
  352. }
  353.  
  354. // 简单的异步等待函数(以毫秒为单位)
  355. function sleep(ms) {
  356. return new Promise(resolve => setTimeout(resolve, ms));
  357. }
  358.  
  359. function updateControlExchangeButton(isRunning,countLeft) {
  360. if (isRunning) {
  361. controlExchangeButton.textContent = `停止兑换 剩余请求 ${countLeft}`;
  362. controlExchangeButton.style.backgroundColor = 'green';
  363. } else {
  364. controlExchangeButton.textContent = '启动兑换 ✔';
  365. controlExchangeButton.style.backgroundColor ='red';
  366. }
  367. }
  368.  
  369. // 页面加载完成后显示悬浮窗
  370. showOverlay();
  371. }
  372. })();