// ==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 Vieira // @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 // @downloadURL none // ==/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); })();