Auto Mining Notifier

Tự động kiểm tra và thông báo kết quả khai thác

Per 20-05-2025. Zie de nieuwste versie.

// ==UserScript==
// @name         Auto Mining Notifier
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Tự động kiểm tra và thông báo kết quả khai thác
// @match        https://cmangax2.com/*
// @grant        GM.xmlHttpRequest
// @grant        GM_notification
// @connect      api.telegram.org
// @connect      cmangax2.com
// ==/UserScript==

(function() {
    'use strict';
    const priorityItem = {
        "pet_heart_bag": "Túi thú tâm",
        "add_option": "Tinh Luyện Châu",
        "job_exp_3": "Thông Thạo Quyển Lv3",
        "job_exp_2": "Thông Thạo Quyển Lv2",
        "job_exp_1": "Thông Thạo Quyển Lv1",
        "medicinal_exp_1": "Tăng Ích Đan Lv1",
        "medicinal_exp_2": "Tăng Ích Đan Lv2",
        "medicinal_exp_3": "Tăng Ích Đan Lv3",
        "medicinal_exp_4": "Tăng Ích Đan Lv4",
        "equipment_upgrade_2": "Trung phẩm Thiên Mộc Thạch",
        "egg_super_fragment": "Mảnh trứng thần thú",
        "egg_rare": "Trứng hiếm",
        "pet_exp_chest" : "Rương thú đan"
    };

    const priceInMarket = {
        "pet_heart_bag": 100,
        "add_option": 25,
        "job_exp_3": 3,
        "job_exp_2": 0.4,
        "job_exp_1": 0.1,
        "medicinal_exp_1": 1.2,
        "medicinal_exp_2": 2.4,
        "medicinal_exp_3": 5,
        "medicinal_exp_4": 8,
        "equipment_upgrade_2": 25,
        "egg_super_fragment": 5,
        "egg_rare": 35,
        "pet_exp_chest": 5
    };
    const RARE_COLORS = {
        4: { name: '🔥 Truyền Thuyết', color: '#ff0000' },
        3: { name: '📜 Sử Thi', color: '#c700ff' },
        2: { name: '🛡️ Hiếm', color: '#0099ff' },
        1: { name: '⚔️ Thường', color: '#666666' },
        0: { name: '❌ Không xác định', color: '#000000' }
    };

    const NOTIFICATION_CONFIG = {
        TELEGRAM: {
            token: 'Thay bằng token bằng cách tìm botfather rồi nhập /mybots rồi chọn token',
            chatId: 'Thay bằng chat id bằng cách tìm userinfo rồi start là xong'
        },
        DISCORD: {
            webhookUrl: 'https://discord.com/api/webhooks/your-webhook-url' // Thay thế bằng webhook của bạn
        },
        MIN_VALUE: 25
    };

    let lastSentHash = ''; // Lưu trạng thái lần gửi cuối
    let isRunning = false; // Cờ kiểm soát quá trình chạy

    const calculateValue = (reward) => {
        let total = 0;
        const validItems = [];

        for (const itemKey in reward) {
            if (priorityItem[itemKey]) {
                const amount = reward[itemKey].amount || 0;
                const price = priceInMarket[itemKey] || 0;

                if (amount > 0 && price > 0) {
                    const value = amount * price;
                    total += value;
                    validItems.push({ [priorityItem[itemKey]]: amount });
                }
            }
        }

        return { total, validItems };
    };

    const processMiner = async (miner, area, index) => {
        try {
            const data = JSON.parse(miner.data);
            const reward = data.miner?.reward;

            //const isProtect = data.miner?.protect === true;
            const isProtect = !!data.miner?.protect;

            if (!reward || typeof reward !== 'object' || isProtect) return null;

            const { total, validItems } = calculateValue(reward);
            if (total <= 0) return null;

            return {
                area: area,
                rare: data.rare,
                stt: index + 1,
                character_id: miner.target,
                author: data.miner?.info?.name,
                total_value: total,
                valid_items: validItems,
                isProtect:false
            };
        } catch (e) {
            console.error(`Error processing miner: ${e}`);
            return null;
        }
    };



    const processArea = async (area) => {
        try {
            const response = await fetch(
                `https://cmangax2.com/api/score_list?type=battle_mine&area=${area}`
            );
            const miners = await response.json();

            const minersPromises = miners.map((miner, index) =>processMiner(miner, area, index));

            const areaResults = await Promise.all(minersPromises);
            return areaResults.filter(item => item !== null);
        } catch (e) {
            console.error(`Error processing area ${area}: ${e}`);
            GM_notification(`Lỗi khi xử lý tầng ${area}: ${e.message}`, 'Lỗi');
            return [];
        }
    };




    const getHmkLevel = async () => {
        const areas = Array.from({ length: 11 }, (_, i) => i + 1);

        const areaPromises = areas.map(area => processArea(area));
        const allResults = await Promise.all(areaPromises);

        return allResults.flat().sort((a, b) => b.total_value - a.total_value);
    };

    const sendToTelegram = async (message) => {
        const token = '8178445381:AAEL5AHPsPcsLYZa5qQvnWPI-3EQI3gMj04';
        const chatId = '5709122878';

        return new Promise((resolve) => {
            GM.xmlHttpRequest({
                method: 'POST',
                url: `https://api.telegram.org/bot${token}/sendMessage`,
                headers: {
                    'Content-Type': 'application/json'
                },
                data: JSON.stringify({
                    chat_id: chatId,
                    text: message,
                    parse_mode: 'HTML'
                }),
                onload: (response) => {
                    if (response.status !== 200) {
                        console.error('Lỗi Telegram:', response.responseText);
                    }
                    resolve();
                },
                onerror: (error) => {
                    console.error('Lỗi kết nối Telegram:', error);
                    resolve();
                }
            });
        });
    };
    const sendToDiscord = async (message) => {
        return new Promise((resolve) => {
            GM.xmlHttpRequest({
                method: 'POST',
                url: NOTIFICATION_CONFIG.DISCORD.webhookUrl,
                headers: {
                    'Content-Type': 'application/json'
                },
                data: JSON.stringify({
                    content: message,
                    embeds: [{
                        description: message.replace(/<[^>]+>/g, ''),
                        color: 0x00ff00
                    }]
                }),
                onload: (response) => {
                    if (response.status < 200 || response.status >= 300) {
                        console.error('Lỗi Discord:', response.responseText);
                    }
                    resolve();
                },
                onerror: (error) => {
                    console.error('Lỗi kết nối Discord:', error);
                    resolve();
                }
            });
        });
    };

    const formatForDiscord = (results) => {
        return results.map(item => {
            const rare = parseInt(item.rare) || 0;
            const rareInfo = RARE_COLORS[rare] || RARE_COLORS[0];
            return `**#${item.stt}** - Tầng ${item.area}
• Rare: ${rareInfo.name}
• Tác giả: ${item.author || 'Ẩn danh'} id: ${item.character_id}
• Giá trị: ${item.total_value.toFixed(2)}💰
• Vật phẩm: ${item.valid_items.map(i => `${Object.values(i)[0]}x ${Object.keys(i)[0]}`).join(', ')}`
        }).join('\n\n');
    };

    const formatResults = (results) => {
        const filtered = results.filter(item => item.total_value >= 25 && item.isProtect === false);
        if (filtered.length === 0) return null;

        const currentHash = JSON.stringify(filtered);
        if (currentHash === lastSentHash) return null;

        lastSentHash = currentHash;

        const now = new Date();
        const options = {
            timeZone: 'Asia/Ho_Chi_Minh',
            hour12: false,
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        };

        const vnTime = new Intl.DateTimeFormat('vi-VN', options)
        .format(now)
        .replace(/(\d+)\/(\d+)\/(\d+),/, '$1-$2-$3');
        let message = `📊 <b>KẾT QUẢ KHAI THÁC MỚI LÚC ${vnTime}</b>\n\n`;
        filtered.slice(0, 15).forEach((item, index) => {
            const rare = parseInt(item.rare) || 0;
            const rareInfo = RARE_COLORS[rare] || RARE_COLORS[0];
            message += `🏷 <b>#${index + 1}</b>\n`
                     + `┣ Tầng: ${item.area}\n`
                     + `┣ Rare: ${rareInfo.name}\n`
                     + `┣ Vị ttrí ${item.stt}\n`
                     + `┣ Tác giả: ${item.author || 'Ẩn danh'} id: ${item.character_id}\n`
                     + `┣ Giá trị: ${item.total_value.toFixed(2)}💰\n`
                     + `┗ Vật phẩm: ${item.valid_items.map(i => `${Object.values(i)[0]}x${Object.keys(i)[0]}`).join('\n')}\n\n`;
        });
        return message;
    };

    const checkAndNotify = async () => {
        if (isRunning) return;
        isRunning = true;

        try {
            const results = await getHmkLevel();
            const telegramMessage = formatResults(results);
            const discordMessage = formatForDiscord(results.filter(item => item.total_value >= NOTIFICATION_CONFIG.MIN_VALUE));
            if (telegramMessage) {
                await Promise.all([
                    sendToTelegram(telegramMessage),
                    sendToDiscord(discordMessage)
                ]);
                GM_notification('Phát hiện khoáng mới!', 'Thành công');
                GM_notification('Đã gửi thông báo đến Telegram & Discord!', 'Thành công');
            }
        } catch (e) {
            GM_notification(`Lỗi hệ thống: ${e.message}`, 'Lỗi');
        } finally {
            isRunning = false;
        }
    };

    //Kiểm tra định kỳ
    setTimeout(function runner() {
        checkAndNotify();
        setTimeout(runner, 30000);
    }, 1000);

    //Nút manual check
    //const btn = document.createElement('button');
    //btn.style = 'position: fixed; bottom: 20px; right: 20px; z-index: 9999; padding: 10px;';
    //btn.textContent = 'Kiểm tra ngay';
    //btn.onclick = checkAndNotify;
    //document.body.appendChild(btn);
})();