Greasy Fork

MZ - Youth Exchange (/16)

Sends new youth player data to Firebase when exchanging youth players

目前为 2024-12-11 提交的版本。查看 最新版本

// ==UserScript==
// @name         MZ - Youth Exchange (/16)
// @namespace    douglaskampl
// @version      2.9
// @description  Sends new youth player data to Firebase when exchanging youth players
// @author       Douglas
// @match        *://www.managerzone.com/?p=youth_academy*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
// @grant        GM.xmlHttpRequest
// @require      https://cdn.jsdelivr.net/npm/sweetalert2@11
// @connect      *
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const CONFIG = {
        USERS: {
            douglaskampl: 'BR' /* You can put your username and country/country code here. */
        },
        YOUTH_AGE: 16,
        ENDPOINTS: {
            COUNTRIES: 'https://u18mz.vercel.app/json/countries.json',
            WORKER: 'https://youth-exchange-worker.douglasdotv.workers.dev/',
            SCOUT: 'https://www.managerzone.com/ajax.php?p=players&sub=scout_report&pid=null&sport=soccer',
            MANAGER: 'http://www.managerzone.com/xml/manager_data.php'
        },
        SKILLS: [
            "speed", "stamina", "playIntelligence", "passing", "shooting",
            "heading", "keeping", "ballControl", "tackling", "aerialPassing", "setPlays",
            "experience", "form"
        ]
    };

    let state = {
        username: 'Unknown',
        nationality: 'Unknown',
        storedPlayerData: null,
        dataReady: false,
        lastPlayerID: null,
        currentSeason: document.querySelector('#header-stats-wrapper h5.linked')?.textContent.match(/(\d+)/)?.[1]
    };

    const showToast = (color, message) => {
        const icons = { blue: 'info', green: 'success', orange: 'warning', red: 'error' };
        Swal.fire({
            toast: true,
            position: 'bottom-right',
            iconColor: color,
            icon: icons[color] || 'error',
            title: message,
            showConfirmButton: false,
            timer: 3000,
            background: color,
            color: 'white'
        });
    };

    const request = async (url, options = {}) => {
        return new Promise((resolve, reject) => {
            GM.xmlHttpRequest({
                method: options.method || 'GET',
                url,
                headers: {
                    'Content-Type': 'application/json',
                    'Origin': 'https://www.managerzone.com',
                    ...options.headers
                },
                data: options.data,
                onload: resolve,
                onerror: reject
            });
        });
    };

    const handleApiError = (error, message) => {
        console.error(message, error);
        showToast('red', message);
        return null;
    };

    const getPlayerData = (playerContainer) => {
        if (!playerContainer) return null;

        const stats = {};
        CONFIG.SKILLS.forEach((skill, index) => {
            const row = playerContainer.querySelectorAll('.player_skills tr')[index];
            const value = row?.querySelector('.skillval span')?.textContent.trim();
            stats[skill] = value ? parseInt(value) : 0;
        });

        return {
            playerID: playerContainer.querySelector('.player_id_span')?.textContent,
            playerName: playerContainer.querySelector('.player_name')?.textContent,
            totalSkillBalls: playerContainer.querySelectorAll('tbody > tr')[6]?.querySelector('.bold')?.textContent,
            stats
        };
    };

    const extractSkills = (doc) => {
        const dataList = doc.querySelectorAll('dl > dd');
        const getSkills = (container) =>
            Array.from(container.querySelectorAll('li > span:last-child'))
                .map(span => span.textContent.trim());

        const [hpSkills = [], lpSkills = []] = [dataList[0], dataList[1]].map(getSkills);

        return {
            hp: dataList[0]?.querySelectorAll('.lit')?.length || 0,
            lp: dataList[1]?.querySelectorAll('.lit')?.length || 0,
            trainingSpeed: dataList[2]?.querySelectorAll('.lit')?.length || 0,
            firstHpSkill: hpSkills[0] || '',
            secondHpSkill: hpSkills[1] || '',
            firstLpSkill: lpSkills[0] || '',
            secondLpSkill: lpSkills[1] || ''
        };
    };

    const extractPlayerData = async () => {
        const playerContainer = document.getElementById("thePlayers_x");
        const currentPlayerID = playerContainer?.querySelector('.player_id_span')?.textContent;

        if (!playerContainer || (currentPlayerID === state.lastPlayerID && state.storedPlayerData)) {
            return;
        }

        state.lastPlayerID = currentPlayerID;
        state.dataReady = false;
        showToast('orange', '🔥');

        try {
            const response = await request(CONFIG.ENDPOINTS.SCOUT);
            const doc = new DOMParser().parseFromString(
                response.responseText.replace(/Trzxyvopaxis/g, ''),
                'text/html'
            );

            const basicData = getPlayerData(playerContainer);
            const skills = extractSkills(doc);

            state.storedPlayerData = {
                ...basicData,
                ...skills,
                age: CONFIG.YOUTH_AGE,
                country: state.nationality,
                owner: state.username,
                season: parseInt(state.currentSeason, 10)
            };

            state.dataReady = true;
            showToast('green', 'Data ready');
            console.log('Data extracted:', state.storedPlayerData);
        } catch (error) {
            handleApiError(error, 'Failed to extract player data');
        }
    };

    const sendData = async () => {
        if (!state.dataReady) {
            showToast('red', 'Data not ready');
            return false;
        }

        try {
            showToast('blue', 'Sending...');
            const response = await request(CONFIG.ENDPOINTS.WORKER, {
                method: 'POST',
                data: JSON.stringify(state.storedPlayerData)
            });

            if (response.status >= 200 && response.status < 300) {
                showToast('green', 'Data sent successfully');
                return true;
            }

            throw new Error(`HTTP ${response.status}: ${response.responseText}`);
        } catch (error) {
            handleApiError(error, 'Failed to send data');
            return false;
        }
    };

    const attachButtonListeners = () => {
        ['#exchange_button', '#discard_youth_button'].forEach(selector => {
            const button = document.querySelector(selector);
            if (button && !button.dataset.listenerAdded) {
                button.addEventListener('click', async (event) => {
                    if (!state.dataReady) {
                        event.preventDefault();
                        showToast('red', 'Please wait for data');
                        return;
                    }
                    await sendData();
                });
                button.dataset.listenerAdded = true;
            }
        });
    };

    const init = async () => {
        state.username = document.getElementById('header-username')?.textContent || 'Unknown';
        state.nationality = CONFIG.USERS[state.username] || 'Unknown';

        if (!state.nationality || state.nationality === 'Unknown') {
            try {
                const response = await request(
                    `${CONFIG.ENDPOINTS.MANAGER}?sport_id=1&username=${state.username}`
                );
                const doc = new DOMParser().parseFromString(response.responseText, 'text/xml');
                state.nationality = doc.querySelector('UserData')?.getAttribute('countryShortname') || 'Unknown';
            } catch (error) {
                handleApiError(error, 'Failed to fetch nationality');
            }
        }

        const observer = new MutationObserver(() => {
            extractPlayerData();
            attachButtonListeners();
        });

        const playerContainer = document.getElementById("thePlayers_x");
        if (playerContainer) {
            observer.observe(playerContainer, { childList: true, subtree: true });
            extractPlayerData();
            attachButtonListeners();
        }
    };

    window.addEventListener('load', init);
})();