Greasy Fork

来自缓存

朱雀自动转盘抽奖及统计

实现朱雀的抽奖功能,自动获取CSRF Token与Cookie,并显示抽奖结果,支持进度显示和停止功能,抽奖之后可以一键出售道具和上传

// ==UserScript==
// @name         朱雀自动转盘抽奖及统计
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  实现朱雀的抽奖功能,自动获取CSRF Token与Cookie,并显示抽奖结果,支持进度显示和停止功能,抽奖之后可以一键出售道具和上传
// @author       banner
// @match        https://zhuque.in/*
// @grant        none
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 定义奖品信息和对应价值
    const prizeMap = {
        "1": { "Name": "一等奖: 改名卡", "Value": 240000 },
        "2": { "Name": "二等奖: 神佑(VIP) 7 天卡", "Value": 80000 },
        "3": { "Name": "三等奖: 邀请卡", "Value": 64000 },
        "4": { "Name": "四等奖: 自动释放技能道具卡 7 天卡", "Value": 24000 },
        "5": { "Name": "五等奖: 上传 20 GiB", "Value": 2280 },
        "6": { "Name": "六等奖: 上传 10 GiB", "Value": 1140 },
        "7": { "Name": "未中奖", "Value": 0 }
    };

    // 全局状态变量
    let isRunning = false;
    let stopRequested = false;
    let totalCost = 0;
    let totalValue = 0;
    let prizeSummary = {};
    let totalUpload = 0;  // 记录上传的总量

    // 初始化奖品统计
    function resetStats() {
        totalCost = 0;
        totalValue = 0;
        totalUpload = 0;
        prizeSummary = {};
        Object.keys(prizeMap).forEach(prizeId => {
            prizeSummary[prizeId] = { "Count": 0, "TotalValue": 0 };
        });
    }

    // 创建UI界面
    function createUI() {
        setTimeout(() => {
            const container = document.createElement('div');
            container.style.position = 'fixed';
            container.style.top = '10px';
            container.style.right = '10px';
            container.style.backgroundColor = '#fff';
            container.style.padding = '20px';
            container.style.border = '1px solid #ccc';
            container.style.boxShadow = '0px 4px 8px rgba(0,0,0,0.1)';
            container.style.zIndex = '9999';

            const title = document.createElement('h3');
            title.textContent = '抽奖统计';
            container.appendChild(title);

            // 输入区域
            const inputContainer = document.createElement('div');
            inputContainer.style.margin = '10px 0';

            // 抽奖次数输入
            const timesDiv = document.createElement('div');
            timesDiv.style.marginBottom = '10px';
            timesDiv.innerHTML = '<label>抽奖次数: </label><input type="number" value="60" min="1" style="width: 80px;">';
            inputContainer.appendChild(timesDiv);

            // 间隔时间输入
            const intervalDiv = document.createElement('div');
            intervalDiv.style.marginBottom = '10px';
            intervalDiv.innerHTML = '<label>间隔(ms): </label><input type="number" value="300" min="0" style="width: 80px;">';
            inputContainer.appendChild(intervalDiv);

            container.appendChild(inputContainer);

            // 控制按钮
            const button = document.createElement('button');
            button.textContent = '开始抽奖';
            button.style.margin = '10px 0';
            container.appendChild(button);

            // 结果显示区域
            const resultContainer = document.createElement('div');
            resultContainer.style.marginTop = '20px';
            resultContainer.style.borderTop = '1px solid #ccc';
            resultContainer.style.paddingTop = '10px';
            container.appendChild(resultContainer);

            document.body.appendChild(container);

            // 事件监听
            button.addEventListener('click', async () => {
                if (isRunning) {
                    stopRequested = true;
                    return;
                }

                const timesInput = timesDiv.querySelector('input');
                const intervalInput = intervalDiv.querySelector('input');

                const requestTimes = parseInt(timesInput.value) || 10;
                const interval = parseInt(intervalInput.value) || 1000;

                if (requestTimes < 1) {
                    alert('抽奖次数至少为1次');
                    return;
                }

                if (interval < 300) {
                    alert('为了避免给站点服务器带来较大负荷,不建议300ms一下的间隔,建议将间隔时长调制500ms以上');
                    return;
                }

                isRunning = true;
                stopRequested = false;
                button.textContent = '停止抽奖';
                resetStats();

                resultContainer.innerHTML = `
                    <div class="status">准备中...</div>
                    <div class="progress">当前进度: 0/${requestTimes}</div>
                    <div class="results"></div>
                    <button class="sellButton" style="display: none;">一键出售</button>
                `;

                try {
                    for (let i = 1; i <= requestTimes; i++) {
                        if (stopRequested) break;

                        await sendRequest();
                        await new Promise(r => setTimeout(r, interval));

                        // 更新进度显示
                        resultContainer.querySelector('.progress').textContent =
                            `当前进度: ${i}/${requestTimes}`;
                    }
                } finally {
                    isRunning = false;
                    button.textContent = '开始抽奖';
                    updateResults(resultContainer);

                    // 显示出售按钮
                    const sellButton = resultContainer.querySelector('.sellButton');
                    sellButton.style.display = 'inline-block';

                    // 销售按钮点击事件
                    sellButton.addEventListener('click', async () => {
                        await handleSellRequest(); // 执行出售请求
                    });
                }
            });
        }, 1000);  // 延迟1秒执行UI创建
    }

    // 发送抽奖请求
    async function sendRequest() {
        try {
            const response = await fetch("https://zhuque.in/api/gaming/spinThePrizeWheel", {
                method: "POST",
                headers: {
                    "X-Csrf-Token": document.querySelector('meta[name="x-csrf-token"]').content,
                    "Cookie": document.cookie
                }
            });

            if (response.ok) {
                const data = await response.json();
                const prizeId = String(data.data.prize);

                if (prizeMap[prizeId]) {
                    prizeSummary[prizeId].Count++;
                    prizeSummary[prizeId].TotalValue += prizeMap[prizeId].Value;
                    totalCost += 1500;
                    totalValue += prizeMap[prizeId].Value;

                    // 处理上传量
                    if (prizeId === "5") {
                        totalUpload += 20;  // 上传20 GiB
                    } else if (prizeId === "6") {
                        totalUpload += 10;  // 上传10 GiB
                    }
                }
            }
        } catch (error) {
            console.error('请求失败:', error);
        }
    }

    // 更新结果展示
    function updateResults(container) {
        let html = '<h4>抽奖结果:</h4>';

        // 按价值降序排列
        const sorted = Object.entries(prizeMap)
            .sort((a, b) => b[1].Value - a[1].Value)
            .forEach(([id, prize]) => {
                const count = prizeSummary[id].Count;
                html += `${prize.Name}: ${count}次 (价值 ${prizeSummary[id].TotalValue}灵石)<br>`;
            });

        html += `<br>总消耗: ${totalCost}灵石<br>`;
        html += `总价值: ${totalValue}灵石<br>`;
        html += `<b>净${totalValue >= totalCost ? '盈利' : '亏损'}: ${Math.abs(totalValue - totalCost)}灵石</b>`;

        container.querySelector('.results').innerHTML = html;
    }

    // 处理出售请求(包括回收与出售上传量)
    async function handleSellRequest() {
        let allRecycleSuccess = true;  // 标记是否所有回收操作都成功

        // 首先回收道具:ID 1, 2, 3, 4
        for (let id = 1; id <= 4; id++) {
            const prizeCount = prizeSummary[id] ? prizeSummary[id].Count : 0;
            if (prizeCount > 0) {
                // 回收每个道具的数量
                const recycleSuccess = await recycleMagicCard(id, prizeCount);
                if (!recycleSuccess) {
                    allRecycleSuccess = false;  // 如果有回收失败,标记为失败
                }
            }
        }



        // 然后出售上传量:仅处理 ID 为 5 和 6 的上传量
        if (totalUpload > 0) {
            // 计算出售的总上传量,按 GiB 出售
            const totalBonus = 127 * totalUpload; // 每 GiB 127 灵石
            const response = await fetch("https://zhuque.in/api/transaction/create", {
                method: "POST",
                headers: {
                    "X-Csrf-Token": document.querySelector('meta[name="x-csrf-token"]').content,
                    "Cookie": document.cookie,
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({
                    type: 2,
                    unit: "GiB",
                    bonus: totalBonus,
                    upload: totalUpload
                })
            });

            if (response.ok) {
                console.log(`成功提交,交易上传 ${totalUpload} GiB,预计获得 ${totalUpload * 127} 灵石`);
            } else {
                const errorText = await response.text();  // 获取错误信息
                console.log(`出售失败: ${errorText}`);
                allRecycleSuccess = false;  // 如果有回收失败,标记为失败
            }
        } else {
            console.log('没有上传量可出售');
        }

        // 如果所有道具回收成功,提示用户
        if (allRecycleSuccess) {
            console.log('所有道具回收成功!');
            alert('所有道具回收成功!');
        } else {
            alert('道具回收失败,错误详情查看控制台')
        }
    }

    // 回收道具:ID 1, 2, 3, 4
    async function recycleMagicCard(id, count) {
        let success = true;  // 标记是否回收成功

        // 回收多个道具的情况,循环回收 `count` 次
        for (let i = 0; i < count; i++) {
            const response = await fetch("https://zhuque.in/api/mall/recycleMagicCard", {
                method: "POST",
                headers: {
                    "X-Csrf-Token": document.querySelector('meta[name="x-csrf-token"]').content,
                    "Cookie": document.cookie,
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({ id: id })
            });

            if (response.ok) {
                console.log(`道具 ID ${id} 第 ${i + 1} 次回收成功!`);
            } else {
                const errorText = await response.text();
                console.log(`回收失败: ${errorText}`);
                success = false;  // 如果有任何失败,标记为失败
            }

            // 添加 100ms 的延迟
            await new Promise(r => setTimeout(r, 100));
        }

        return success;  // 返回回收是否成功
    }


    // 初始化
    resetStats();
    createUI();
})();