您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Alice 抽奖脚本,API直连高速抽奖,并新增“一键全梭哈”功能。
// ==UserScript== // @name Alice 抽奖脚本 // @namespace http://tampermonkey.net/ // @version 4.1 // @description Alice 抽奖脚本,API直连高速抽奖,并新增“一键全梭哈”功能。 // @author Gemini // @match *://*/lottery/pool* // @grant GM_addStyle // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; // ================= 全局常量与状态变量 ================= const COST_PER_DRAW = 20; // 单次抽奖成本 let isAutoDrawing = false; // 脚本是否正在执行 let targetDraws = 0; // 目标抽奖次数 let drawCount = 0; // 当前已抽奖次数 let successfulDraws = 0; // 成功抽奖次数 let failedDraws = 0; // 失败抽奖次数 // ================= 核心抽奖逻辑 (API直连) ================= async function apiCall(url) { try { const response = await fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' }, }); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); return await response.json(); } catch (error) { console.error('API call failed:', error); return { code: -1, message: error.message }; } } async function performApiDraw(poolId) { const apiUrl = `/api/lottery/lot?action=draw&pool_id=${poolId}`; const response = await apiCall(apiUrl); drawCount++; if (response && (response.code === 1 || response.code === '1')) { successfulDraws++; const prizeInfo = response.data.is_winner ? `🎉 抽中: ${response.data.prize.name}` : '... 未中奖'; console.log(`第 ${drawCount}/${targetDraws} 次尝试成功。${prizeInfo}`); updateStatus(`高速抽奖中... [成功: ${successfulDraws} / 失败: ${failedDraws}] (${drawCount}/${targetDraws})`); return true; } else { failedDraws++; const errorMessage = response.message || '未知错误'; console.error(`第 ${drawCount}/${targetDraws} 次尝试失败: ${errorMessage}`); updateStatus(`高速抽奖中... [成功: ${successfulDraws} / 失败: ${failedDraws}] (${drawCount}/${targetDraws})`); if (errorMessage.includes('point') || errorMessage.includes('积分')) { return false; } return true; } } // ================= 控制函数 ================= async function startAutoDraw() { if (isAutoDrawing) return; const limitInput = document.getElementById('custom-draw-input'); const delayInput = document.getElementById('request-delay-input'); targetDraws = parseInt(limitInput.value, 10); const delay = parseInt(delayInput.value, 10); if (isNaN(targetDraws) || targetDraws <= 0) { updateStatus('错误:请输入有效的抽奖次数!'); return; } if (isNaN(delay) || delay < 100) { updateStatus('错误:延迟需大于等于100ms!'); return; } const availableDrawButton = document.querySelector('.draw-button:not(:disabled)'); if (!availableDrawButton) { updateStatus('错误:找不到可抽奖的奖池!'); return; } const onclickAttr = availableDrawButton.getAttribute('onclick'); const poolIdMatch = onclickAttr.match(/drawLottery\((\d+)\)/); if (!poolIdMatch || !poolIdMatch[1]) { updateStatus('错误:无法解析抽奖池ID!'); return; } const poolId = poolIdMatch[1]; console.log(`锁定抽奖池ID: ${poolId}`); isAutoDrawing = true; drawCount = 0; successfulDraws = 0; failedDraws = 0; toggleControls(true); updateStatus(`任务开始,目标: ${targetDraws}次,延迟: ${delay}ms`); console.log(`自动抽奖任务开始,目标次数: ${targetDraws}, 请求延迟: ${delay}ms`); for (let i = 0; i < targetDraws; i++) { if (!isAutoDrawing) { console.log('任务被手动停止。'); break; } const continueTask = await performApiDraw(poolId); if (!continueTask) { console.log('检测到严重错误(可能积分不足),任务提前终止。'); break; } await new Promise(resolve => setTimeout(resolve, delay)); } console.log('抽奖任务执行完毕。'); stopAutoDraw(true); } function stopAutoDraw(autoFinished = false) { isAutoDrawing = false; toggleControls(false); if (autoFinished) { updateStatus(`任务完成![成功: ${successfulDraws} / 失败: ${failedDraws}] 总计: ${drawCount}次。正在刷新积分...`); } else { updateStatus(`任务已手动停止于第 ${drawCount} 次。正在刷新积分...`); } console.log('正在刷新页面积分和记录...'); if (typeof loadUserInfo === 'function') loadUserInfo(); if (typeof loadRecords === 'function') loadRecords(); } function toggleControls(isDrawing) { document.getElementById('custom-draw-input').disabled = isDrawing; document.getElementById('request-delay-input').disabled = isDrawing; document.getElementById('start-draw').disabled = isDrawing; document.getElementById('stop-draw').disabled = !isDrawing; document.getElementById('draw-all-btn').disabled = isDrawing; // [新增] 禁用全梭哈按钮 } /** * [新增] 计算并显示最大可抽奖次数 * @returns {number} - 返回计算出的最大次数 */ function calculateAndDisplayMaxDraws() { const maxDrawsInfoEl = document.getElementById('max-draws-info'); const pointsEl = document.getElementById('user-points'); if (!pointsEl) { maxDrawsInfoEl.textContent = '无法找到您的积分信息。'; return 0; } const pointsText = pointsEl.textContent.replace(/,/g, ''); // 移除逗号 const currentPoints = parseInt(pointsText, 10); if (isNaN(currentPoints)) { maxDrawsInfoEl.textContent = '无法解析您的积分数值。'; return 0; } const maxDraws = Math.floor(currentPoints / COST_PER_DRAW); maxDrawsInfoEl.textContent = `根据您当前的 ${currentPoints.toLocaleString()} 积分,最多可抽奖 ${maxDraws} 次。`; return maxDraws; } /** * [新增] 处理“一键全梭哈”按钮点击事件 */ function handleDrawAll() { const maxDraws = calculateAndDisplayMaxDraws(); if (maxDraws > 0) { document.getElementById('custom-draw-input').value = maxDraws; document.getElementById('start-draw').click(); } else { updateStatus('积分不足,无法执行“一键全梭哈”。'); } } // ================= UI 创建和注入 (版本 4.1) ================= function setupUI() { const container = document.createElement('div'); container.id = 'auto-draw-controller'; container.innerHTML = ` <div class="controller-title">抽奖控制器 v4.1 (高速版)</div> <div class="input-grid"> <div class="input-item"> <label for="custom-draw-input">抽奖次数</label> <input type="number" id="custom-draw-input" class="controller-input" placeholder="例如: 100" min="1"> </div> <div class="input-item"> <label for="request-delay-input">请求延迟(ms)</label> <input type="number" id="request-delay-input" class="controller-input" value="300" min="100"> </div> </div> <div class="max-draws-info" id="max-draws-info">正在计算最大可抽奖次数...</div> <div class="button-group"> <button id="draw-all-btn" class="controller-btn all-in">💰 一键全梭哈</button> <button id="start-draw" class="controller-btn start">🚀 开始抽奖</button> <button id="stop-draw" class="controller-btn stop" disabled>🛑 停止</button> </div> <div id="controller-status" class="controller-status">待命中...</div> `; const targetElement = document.querySelector('.points-card'); if (targetElement) { targetElement.insertAdjacentElement('afterend', container); document.getElementById('start-draw').addEventListener('click', startAutoDraw); document.getElementById('stop-draw').addEventListener('click', () => stopAutoDraw(false)); document.getElementById('draw-all-btn').addEventListener('click', handleDrawAll); // [新增] 绑定事件 calculateAndDisplayMaxDraws(); // [新增] 页面加载后立即计算并显示 } } function updateStatus(message) { const statusEl = document.getElementById('controller-status'); if (statusEl) { statusEl.textContent = message; } } // 添加一些CSS样式 (版本 4.1) GM_addStyle(` #auto-draw-controller { background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 16px; padding: 20px; margin-bottom: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; } .controller-title { font-size: 1.2rem; font-weight: 700; color: #0d47a1; margin-bottom: 16px; text-align: center; } .input-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 10px; } .input-item { display: flex; flex-direction: column; } .input-item label { color: #546e7a; font-size: 0.8rem; font-weight: 600; margin-bottom: 5px; } .controller-input { border: 1px solid #ced4da; padding: 10px 14px; border-radius: 10px; font-size: 1rem; text-align: center; width: 100%; transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; } .controller-input:focus { border-color: #1e88e5; outline: none; box-shadow: 0 0 0 3px rgba(30, 136, 229, 0.25); } .max-draws-info { text-align: center; font-size: 0.85rem; color: #1976d2; margin-bottom: 16px; padding: 8px; background-color: #e3f2fd; border-radius: 8px; } .button-group { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; } .controller-btn { border: none; padding: 12px; border-radius: 12px; font-size: 0.9rem; font-weight: 700; cursor: pointer; transition: all 0.2s ease-in-out; } .controller-btn.start { background: linear-gradient(135deg, #28a745 0%, #218838 100%); color: white; } .controller-btn.all-in { background: linear-gradient(135deg, #ffc107 0%, #ffa000 100%); color: #212529; } .controller-btn.stop { background: linear-gradient(135deg, #d32f2f 0%, #f44336 100%); color: white; } .controller-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); } .controller-btn:disabled, .controller-input:disabled { background: #e0e0e0; color: #9e9e9e; cursor: not-allowed; transform: none; box-shadow: none; opacity: 0.7; } .controller-status { text-align: center; margin-top: 16px; font-size: 0.95rem; color: #546e7a; font-weight: 500; background: #e3f2fd; padding: 8px; border-radius: 8px; } `); window.addEventListener('load', setupUI); })();