您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在抽奖页面显示用户信息并支持复制功能
// ==UserScript== // @name 115 助力助手 - 抽奖页面专用版 // @namespace http://tampermonkey.net/ // @version 1.6 // @description 在抽奖页面显示用户信息并支持复制功能 // @author allen666 // @match https://f.115.com/social/games/lucky5* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; let isRunning = false; let controller = new AbortController(); let startTime; let completedRequests = 0; let isMinimized = false; // 防止重复加载 if (document.getElementById('boost-panel')) return; // ✅ 严格限定:只在抽奖页面显示 if (!window.location.href.includes('https://f.115.com/social/games/lucky5')) return; // 创建侧边栏控制按钮(可拖动) const createToggleButton = () => { const btn = document.createElement('button'); btn.id = 'boost-toggle-btn'; Object.assign(btn.style, { position: 'fixed', top: '200px', right: '0', width: '80px', height: '60px', // 增加高度 backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '4px 0 0 4px', cursor: 'move', zIndex: '9999', fontSize: '14px', boxShadow: '0 2px 6px rgba(0,0,0,0.2)', textAlign: 'center', lineHeight: '1.3', padding: '8px 0' }); btn.innerHTML = '助力工具<br><span style="font-size:10px;font-style:italic;">by allen666</span><br><span style="font-size:10px;display:block;">v1.6</span>'; let isDragging = false; let offsetX, offsetY; btn.addEventListener('mousedown', (e) => { if (e.target.tagName !== 'BUTTON') return; isDragging = true; offsetX = e.clientX - parseInt(btn.style.right || '0'); offsetY = e.clientY - parseInt(btn.style.top || '200px'); e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const right = window.innerWidth - (e.clientX + offsetX); btn.style.top = `${e.clientY - offsetY}px`; btn.style.right = `${Math.max(right, 0)}px`; }); document.addEventListener('mouseup', () => { isDragging = false; }); btn.addEventListener('click', (e) => { if (e.target.tagName === 'BUTTON' || e.target.parentElement.tagName === 'BUTTON') { togglePanel(); } }); return btn; }; // 创建主面板 const createPanel = () => { const panel = document.createElement('div'); panel.id = 'boost-panel'; Object.assign(panel.style, { position: 'fixed', top: '120px', right: '-320px', width: '300px', height: '600px', backgroundColor: 'white', border: '1px solid #ddd', borderRadius: '8px 0 0 8px', boxShadow: '0 4px 12px rgba(0,0,0,0.15)', zIndex: '9999', transition: 'right 0.3s ease, height 0.3s ease', overflow: 'hidden', fontFamily: 'Arial, sans-serif', }); panel.innerHTML = ` <div id="panel-header" style="padding: 12px; background: #007bff; color: white; font-weight: bold; cursor: move; display: flex; justify-content: space-between; align-items: center;"> <div style="line-height: 1.4;"> <div>115 助力工具</div> </div> <div style="display: flex; gap: 10px;"> <button id="minimize-btn" style="background:none;border:none;color:white;font-size:16px;cursor:pointer;">−</button> <button id="close-btn" style="background:none;border:none;color:white;font-size:16px;cursor:pointer;">×</button> </div> </div> <div id="panel-content" style="padding: 16px; display: block;"> <!-- 用户信息 --> <div id="user-info" style="margin-bottom:12px;font-size:12px;line-height:1.5;"> <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;"> <span>用户 ID:</span> <div style="display:flex;align-items:center;gap:4px;"> <span id="user-id">获取中...</span> <button id="copy-user-id" class="copy-btn" style="background:#eee;border:none;width:24px;height:20px;font-size:10px;cursor:pointer;border-radius:2px;"> 复制 </button> </div> </div> <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;"> <span>我的助力码:</span> <div style="display:flex;align-items:center;gap:4px;"> <span id="my-boost-code">获取中...</span> <button id="copy-boost-code" class="copy-btn" style="background:#eee;border:none;width:24px;height:20px;font-size:10px;cursor:pointer;border-radius:2px;"> 复制 </button> </div> </div> </div> <label style="display:block;margin-bottom:8px;font-size:14px;">助力码列表(每行一个)</label> <textarea id="boost-codes" rows="6" style="width:100%;font-family:monospace;font-size:12px;padding:8px; border:1px solid #ccc;border-radius:4px;resize:none;" placeholder="ABC123 XYZ789"></textarea> <div style="margin-top:4px;color:red;font-size:12px;" id="boost-limit-tip"></div> <div id="action-buttons" style="margin-top:8px;display:flex;gap:8px;"> <button id="start-boost" style="flex:1;background:#28a745;color:white; border:none;padding:10px 0;border-radius:4px;font-size:14px; cursor:pointer;">开始助力</button> </div> <div id="stats" style="margin-top:12px;font-size:12px;"> <div>总数: <span id="total">0</span></div> <div style="color:green;">成功: <span id="success">0</span></div> <div style="color:orange;">重复: <span id="duplicate">0</span></div> <div style="color:#666;">速率: <span id="rate">0</span> req/s</div> </div> <div style="margin-top:16px;font-size:14px;font-weight:bold;">执行日志</div> <div id="log-area" style="height:200px;overflow-y:auto;border:1px solid #eee; padding:8px;background:#f9f9f9;font-size:12px;"> <div class="log-item" style="color:#666;">等待启动...</div> </div> <!-- 加载动画 --> <div id="loading" style="display:none;text-align:center;margin-top:8px;"> <div style="display:inline-block;width:16px;height:16px;border:2px solid #ddd;border-top-color:#007bff;border-radius:50%;animation:spin 1s linear infinite;"></div> <span style="margin-left:8px;font-size:12px;color:#666;">处理中...</span> </div> </div> <style> @keyframes spin { to { transform: rotate(360deg); } } .copy-success::after { content: ' ✓'; color: green; animation: fadeOut 1.5s; } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } </style> `; return panel; }; // 添加日志 function addLog(message, color = 'black') { const logArea = document.getElementById('log-area'); const item = document.createElement('div'); item.className = 'log-item'; item.style.color = color; item.style.margin = '4px 0'; item.style.whiteSpace = 'nowrap'; item.style.overflow = 'hidden'; item.style.textOverflow = 'ellipsis'; const time = new Date().toLocaleTimeString(); item.textContent = `[${time}] ${message}`; logArea.appendChild(item); requestAnimationFrame(() => { logArea.scrollTop = logArea.scrollHeight; }); } // 更新统计 function updateStats(key) { const el = document.getElementById(key); const val = parseInt(el.textContent || '0'); el.textContent = val + 1; } // 重置统计 function resetStats() { document.getElementById('success').textContent = '0'; document.getElementById('duplicate').textContent = '0'; document.getElementById('rate').textContent = '0'; } // 更新速率 function updateRate() { if (!startTime) return; const elapsed = (Date.now() - startTime) / 1000; const rate = elapsed > 0 ? (completedRequests / elapsed).toFixed(1) : '0'; document.getElementById('rate').textContent = rate; } // 获取用户信息 async function fetchUserInfo() { try { const response = await fetch(`https://act.115.com/api/1.0/web/1.0/invite_boost/user_info?_t=${Date.now()}`, { method: 'GET', credentials: 'include' }); if (!response.ok) throw new Error('网络错误'); const data = await response.json(); if (data.state === 1) { const userInfo = data.data.user_info; const stats = data.data.stats; // 更新用户信息 document.getElementById('user-id').textContent = userInfo.user_id; document.getElementById('my-boost-code').textContent = userInfo.boost_code; // // 更新状态显示 // const canBoostEl = document.getElementById('can-boost-status'); // const canExchangeEl = document.getElementById('can-exchange-status'); // if (stats.can_boost) { // canBoostEl.textContent = '能否助力:可助力'; // canBoostEl.style.color = 'green'; // } else { // canBoostEl.textContent = '能否助力:不可助力'; // canBoostEl.style.color = 'red'; // } // if (stats.can_exchange) { // canExchangeEl.textContent = '能否兑换:可兑换'; // canExchangeEl.style.color = 'green'; // } else { // canExchangeEl.textContent = '能否兑换:不可兑换'; // canExchangeEl.style.color = 'red'; // } // 控制开始助力按钮 const startBtn = document.getElementById('start-boost'); const tipEl = document.getElementById('boost-limit-tip'); if (!stats.can_boost) { startBtn.disabled = true; startBtn.style.opacity = '0.6'; startBtn.style.cursor = 'not-allowed'; tipEl.textContent = '当前助力次数已用完'; } else { startBtn.disabled = false; startBtn.style.opacity = '1'; startBtn.style.cursor = 'pointer'; tipEl.textContent = ''; } addLog('✅ 用户信息获取成功', 'green'); return data; } else { addLog(`❌ 获取用户信息失败: ${data.message}`, 'red'); return null; } } catch (err) { addLog('❌ 网络错误,无法获取用户信息', 'red'); console.error(err); return null; } } // 复制到剪贴板(兼容性增强版) function copyToClipboard(text, button, successText = '已复制') { // 创建临时 textarea 元素用于复制 const tempTextarea = document.createElement('textarea'); tempTextarea.value = text; tempTextarea.setAttribute('readonly', ''); Object.assign(tempTextarea.style, { position: 'absolute', left: '-9999px', opacity: 0, width: '1px', height: '1px' }); document.body.appendChild(tempTextarea); // 尝试使用现代 Clipboard API if (navigator.clipboard) { navigator.clipboard.writeText(text).then(() => { showCopyFeedback(button, successText); }).catch(err => { console.warn('Clipboard API 失败,回退到 execCommand:', err); fallbackCopy(tempTextarea, button, successText); }); } else { // 浏览器不支持 navigator.clipboard fallbackCopy(tempTextarea, button, successText); } // 移除临时元素 setTimeout(() => { document.body.removeChild(tempTextarea); }, 1000); } // 回退方案:使用 document.execCommand function fallbackCopy(tempTextarea, button, successText) { try { tempTextarea.select(); tempTextarea.setSelectionRange(0, 99999); // 兼容移动端 const successful = document.execCommand('copy'); if (successful) { showCopyFeedback(button, successText); } else { throw new Error('execCommand failed'); } } catch (err) { console.error('复制失败:', err); alert('复制失败,请长按选择并复制'); } } // 显示复制成功反馈 function showCopyFeedback(button, successText) { const originalText = button.textContent; button.textContent = successText; button.classList.add('copy-success'); setTimeout(() => { button.textContent = originalText; button.classList.remove('copy-success'); }, 1500); } // 发送助力请求(带重试机制) async function sendBoost(code, retryCount = 3) { for (let i = 0; i < retryCount; i++) { try { const formData = new FormData(); formData.append('boost_code', code); formData.append('source', 'link'); const response = await fetch('https://act.115.com/api/1.0/web/1.0/invite_boost/accept_invite', { method: 'POST', body: formData, credentials: 'include', signal: controller.signal }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); return data; } catch (err) { if (err.name === 'AbortError') return { state: 0, message: '请求被取消' }; if (i === retryCount - 1) { return { state: 0, message: `网络错误(已重试${retryCount}次)` }; } await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i))); } } } // 主要逻辑 async function startBoost() { if (isRunning) return; const textarea = document.getElementById('boost-codes'); const codes = textarea.value .split('\n') .map(line => line.trim().toUpperCase()) .filter(line => /^[A-Z0-9]{6}$/.test(line)); if (codes.length === 0) { alert('请输入有效的6位助力码(A-Z, 0-9),每行一个'); return; } // 再次检查是否可助力 const stats = await fetchUserInfo(); if (!stats?.data?.stats?.can_boost) { alert('当前助力次数已用完,无法继续助力'); return; } isRunning = true; controller = new AbortController(); startTime = Date.now(); completedRequests = 0; // 冻结输入框和原按钮 textarea.disabled = true; const startBtn = document.getElementById('start-boost'); if (startBtn) startBtn.style.display = 'none'; // 显示加载动画 document.getElementById('loading').style.display = 'block'; // 清除旧的按钮 const actionButtons = document.getElementById('action-buttons'); const existingStop = document.getElementById('stop-boost'); if (existingStop) existingStop.remove(); // 添加“停止”按钮 const stopBtn = document.createElement('button'); stopBtn.id = 'stop-boost'; stopBtn.textContent = '停止助力'; stopBtn.style = 'flex:1;background:#dc3545;color:white;border:none;padding:10px 0;border-radius:4px;font-size:14px;cursor:pointer;'; stopBtn.onclick = () => { isRunning = false; controller.abort(); addLog('🛑 用户手动停止助力', 'red'); finishProcess(); }; actionButtons.appendChild(stopBtn); // 重置并显示总数 resetStats(); document.getElementById('total').textContent = codes.length; // 清空日志 document.getElementById('log-area').innerHTML = ''; addLog(`共发现 ${codes.length} 个有效助力码,开始处理...`, 'blue'); // 逐个处理 for (const code of codes) { if (!isRunning) break; addLog(`正在助力: ${code}`, '#007bff'); const result = await sendBoost(code); if (result.state === 1) { addLog(`✅ 成功助力: ${result.data.inviter_name || '未知用户'}`, 'green'); updateStats('success'); } else if (result.code === 40203004 || result.message.includes('已经')) { addLog(`🟡 已助力过: ${code}`, 'orange'); updateStats('duplicate'); } else { addLog(`❌ 助力失败: ${result.message || '未知错误'}`, 'red'); } completedRequests++; updateRate(); await new Promise(resolve => { if (!isRunning) return resolve(); setTimeout(resolve, 800); }); } finishProcess(); } function finishProcess() { isRunning = false; const stopBtn = document.getElementById('stop-boost'); if (stopBtn) stopBtn.remove(); document.getElementById('loading').style.display = 'none'; const actionButtons = document.getElementById('action-buttons'); actionButtons.innerHTML = ''; const clearBtn = document.createElement('button'); clearBtn.textContent = '清空'; clearBtn.style = 'flex:1;background:#6c757d;color:white;border:none;padding:10px 0;border-radius:4px;font-size:14px;cursor:pointer;'; clearBtn.onclick = clearAll; const saveBtn = document.createElement('button'); saveBtn.textContent = '保存日志'; saveBtn.style = 'flex:1;background:#17a2b8;color:white;border:none;padding:10px 0;border-radius:4px;font-size:14px;cursor:pointer;'; saveBtn.onclick = saveLog; actionButtons.appendChild(clearBtn); actionButtons.appendChild(saveBtn); } function clearAll() { const textarea = document.getElementById('boost-codes'); textarea.value = ''; textarea.disabled = false; const logArea = document.getElementById('log-area'); logArea.innerHTML = '<div class="log-item" style="color:#666;">等待启动...</div>'; document.getElementById('total').textContent = '0'; resetStats(); const actionButtons = document.getElementById('action-buttons'); actionButtons.innerHTML = ` <button id="start-boost" style="flex:1;background:#28a745;color:white; border:none;padding:10px 0;border-radius:4px;font-size:14px; cursor:pointer;">开始助力</button> `; document.getElementById('start-boost').addEventListener('click', startBoost, { once: false }); } function saveLog() { const logArea = document.getElementById('log-area'); const logs = Array.from(logArea.children) .map(el => el.textContent) .join('\n'); const now = new Date(); const filename = `115助力助手-${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}.txt`; const blob = new Blob([logs], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } // 切换面板显示状态 function togglePanel() { const panel = document.getElementById('boost-panel'); if (!panel) return; const currentRight = getComputedStyle(panel).right; if (currentRight === '0px') { panel.style.right = '-320px'; } else { panel.style.right = '0'; if (isMinimized) minimizePanel(false); } } // 最小化/恢复面板 function minimizePanel(minimize = true) { const panel = document.getElementById('boost-panel'); const content = document.getElementById('panel-content'); const minimizeBtn = document.getElementById('minimize-btn'); if (minimize) { content.style.display = 'none'; panel.style.height = '52px'; minimizeBtn.textContent = '□'; isMinimized = true; } else { content.style.display = 'block'; panel.style.height = '600px'; minimizeBtn.textContent = '−'; isMinimized = false; } } // 初始化函数 async function init() { if (document.getElementById('boost-panel')) return; const toggleBtn = createToggleButton(); const panel = createPanel(); document.body.appendChild(toggleBtn); document.body.appendChild(panel); // 先获取用户信息 await fetchUserInfo(); // 绑定事件 document.getElementById('start-boost').addEventListener('click', startBoost, { once: false }); // 绑定复制按钮 document.getElementById('copy-user-id').addEventListener('click', function () { const userId = document.getElementById('user-id').textContent; copyToClipboard(userId, this, '✅'); }); document.getElementById('copy-boost-code').addEventListener('click', function () { const code = document.getElementById('my-boost-code').textContent; copyToClipboard(code, this, '✅'); }); // 最小化按钮 document.getElementById('minimize-btn').addEventListener('click', (e) => { e.stopPropagation(); minimizePanel(!isMinimized); }); // 关闭按钮 document.getElementById('close-btn').addEventListener('click', (e) => { e.stopPropagation(); const panel = document.getElementById('boost-panel'); panel.style.right = '-320px'; }); // 面板头部拖动 const header = document.getElementById('panel-header'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', (e) => { if (e.target.tagName === 'BUTTON') return; isDragging = true; offsetX = e.clientX - parseInt(panel.style.right || '0'); offsetY = e.clientY - parseInt(panel.style.top || '120px'); e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const right = window.innerWidth - (e.clientX + offsetX); const top = e.clientY - offsetY; panel.style.top = `${Math.max(top, 0)}px`; panel.style.right = `${Math.max(right, 0)}px`; }); document.addEventListener('mouseup', () => { isDragging = false; }); } // 页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址