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"
    };

    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
    };
    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' }
    };


    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;
            if (!reward || typeof reward !== 'object') 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
            };
        } 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 formatResults = (results) => {
        const filtered = results.filter(item => item.total_value >= 20);
        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: <span style="color: ${rareInfo.color}">${rareInfo.name}</span>\n`
                     + `┣ Vị ttrí ${item.stt}\n`
                     + `┣ Tác giả: ${item.author || 'Ẩn danh'}\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 message = formatResults(results);

            if (message) {
                await sendToTelegram(message);
                GM_notification('Đã phát hiện kết quả mới!', 'Thông báo');
            }
        } 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);
})();