// ==UserScript== // @name MZ - Friendly Matches Played by Players // @namespace douglaskampl // @version 3.0 // @description Gets the amount of friendlies played by each player during the current week // @author Douglas Vieira // @match https://www.managerzone.com/?p=challenges* // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== GM_addStyle(` .friendly-modal { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.9); backdrop-filter: blur(5px); transform: translateZ(0); opacity: 0; transition: opacity 0.3s ease-out; } .friendly-modal.visible { opacity: 1; } .friendly-modal-content { background: linear-gradient(145deg, #2a2a2a, #1a1a1a); margin: 5% auto; padding: 0; border: 1px solid #444; width: fit-content; max-width: 80%; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); transform: translateY(-20px); opacity: 0; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); } .friendly-modal.visible .friendly-modal-content { transform: translateY(0); opacity: 1; } .friendly-close { color: #888; float: right; font-size: 28px; font-weight: bold; cursor: pointer; padding: 0 10px; transition: color 0.2s ease; } .friendly-close:hover { color: #fff; } .friendly-table { border-collapse: collapse; margin: 0 auto; border: 1px solid #333; background: #111; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } .friendly-cell { border: 1px solid #333; padding: 8px 16px; color: #e0e0e0; transition: background-color 0.2s ease; } .friendly-table tr:hover .friendly-cell { background-color: #1a1a1a; } .friendly-header { background: linear-gradient(90deg, #d6204e, #b81b42); color: white; border: 1px solid #333; padding: 12px 16px; text-transform: uppercase; letter-spacing: 0.5px; font-size: 14px; font-weight: 600; } .friendly-link { color: #e0e0e0; text-decoration: none; position: relative; padding-bottom: 2px; transition: color 0.2s ease; } .friendly-link:hover { color: #d6204e; } .friendly-loading { display: none; justify-content: center; align-items: center; width: 100%; height: 100px; } .friendly-message { color: #d6204e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 16px; text-align: center; animation: pulse 1.5s ease-in-out infinite; } .friendly-button { width: 36px; height: 36px; border-radius: 50%; border: none; cursor: pointer; color: white; background: linear-gradient(145deg, #1e3a8a, #1e40af); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; } .friendly-button:hover { transform: translateY(-2px); box-shadow: 0 6px 8px -2px rgba(0, 0, 0, 0.2); background: linear-gradient(145deg, #1e40af, #1e3a8a); } .friendly-button:active { transform: translateY(0); box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1); } .friendly-text { margin-right: 15px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: #1e3a8a; font-size: 16px; font-weight: 500; text-shadow: 2px 2px 4px rgba(255, 165, 0, 0.3); } @keyframes pulse { 0% { opacity: 0.6; } 50% { opacity: 1; } 100% { opacity: 0.6; } } `); (function() { "use strict"; const UI_TEXT = { BUTTON_TEXT: "Click the circle to see how many matches your players played this week ->", LOADING_TEXT: "Loading…", NO_MATCHES_TEXT: "No friendly matches have been played this week!", PLAYER_COLUMN: "Player", GAMES_COLUMN: "Games This Week" }; class FriendlyMatchTracker { constructor() { this.sport = this.getSport(); this.sportId = this.sport === "soccer" ? 1 : 2; this.challengeTemplateUrl = `https://www.managerzone.com/ajax.php?p=challenge&sub=personal-challenge-template&sport=${this.sport}`; this.teamId = null; this.appearances = new Map(); this.initializeUI(); this.fetchPageData(); } getSport() { return new URL(document.querySelector("#shortcut_link_thezone").href).searchParams.get("sport"); } initializeUI() { this.createModal(); this.createTable(); this.createLoadingElements(); this.addMainButton(); } createModal() { const modal = document.createElement("div"); modal.className = "friendly-modal"; const content = document.createElement("div"); content.className = "friendly-modal-content"; const close = document.createElement("span"); close.className = "friendly-close"; close.innerHTML = "×"; close.onclick = () => this.toggleModal(false); content.appendChild(close); modal.appendChild(content); document.body.appendChild(modal); this.modal = modal; this.modalContent = content; } createTable() { this.table = document.createElement("table"); this.table.className = "friendly-table"; this.modalContent.appendChild(this.table); } createLoadingElements() { const loadingDiv = document.createElement("div"); loadingDiv.className = "friendly-loading"; const message = document.createElement("p"); message.className = "friendly-message"; message.textContent = UI_TEXT.LOADING_TEXT; loadingDiv.appendChild(message); this.modalContent.appendChild(loadingDiv); this.loadingDiv = loadingDiv; this.loadingMessage = message; } addMainButton() { const checkExist = setInterval(() => { const target = document.getElementById("fss-title-heading"); if (target) { clearInterval(checkExist); const container = document.createElement("div"); container.style.display = "flex"; container.style.alignItems = "center"; container.style.marginBottom = "15px"; const text = document.createElement("span"); text.className = "friendly-text"; text.textContent = UI_TEXT.BUTTON_TEXT; const button = document.createElement("button"); button.className = "friendly-button"; button.innerHTML = ''; button.onclick = () => this.toggleModal(true); container.appendChild(text); container.appendChild(button); target.parentNode.insertBefore(container, target); } }, 100); } toggleModal(show) { requestAnimationFrame(() => { if (show) { this.modal.style.display = "block"; requestAnimationFrame(() => { this.modal.classList.add("visible"); if (this.appearances.size === 0) { this.loadingDiv.style.display = "flex"; } }); } else { this.modal.classList.remove("visible"); setTimeout(() => { this.modal.style.display = "none"; this.loadingDiv.style.display = "none"; }, 300); } }); } async fetchPageData() { try { const response = await fetch(window.location.href); const data = await response.text(); const doc = new DOMParser().parseFromString(data, "text/html"); const username = doc.getElementById("header-username").textContent; await this.fetchManagerData(username); } catch (error) { console.warn("Error fetching page data:", error); } } async fetchManagerData(username) { try { const response = await fetch(`https://www.managerzone.com/xml/manager_data.php?sport_id=1&username=${username}`); const xmlDoc = new DOMParser().parseFromString(await response.text(), "text/xml"); const teamElement = Array.from(xmlDoc.getElementsByTagName("Team")) .find(team => team.getAttribute("sport") === this.sport); this.teamId = teamElement.getAttribute("teamId"); await this.fetchChallengeTemplate(); } catch (error) { console.warn("Error fetching manager data:", error); } } async fetchChallengeTemplate() { try { const response = await fetch(this.challengeTemplateUrl); const doc = new DOMParser().parseFromString(await response.text(), "text/html"); const matchesDiv = this.getCurrentWeekMatchesDiv(doc); if (!matchesDiv) { this.showNoMatchesMessage(); return; } const matchIds = this.extractMatchIds(matchesDiv); if (matchIds.length === 0) { this.showNoMatchesMessage(); return; } await this.fetchMatchInfo(matchIds); } catch (error) { console.warn("Error fetching challenge template:", error); } } getCurrentWeekMatchesDiv(doc) { const scheduleDiv = doc.getElementById("friendly_series_schedule"); if (!scheduleDiv) return null; const calendarDiv = scheduleDiv.querySelector(".calendar"); if (!calendarDiv) return null; const calendarForm = calendarDiv.querySelector("#saveMatchTactics"); return calendarForm?.querySelector("div.flex-nowrap.fss-row.fss-gw-wrapper.fss-has-matches"); } extractMatchIds(matchesDiv) { return ["d1", "d3", "d4", "d5", "d7"] .map(className => matchesDiv.querySelector(`.${className}`)) .filter(Boolean) .flatMap(div => Array.from(div.querySelectorAll("a.score-shown:not(.gray)")) .map(link => link.getAttribute("href").split("mid=")[1].split("&")[0]) ); } async fetchMatchInfo(matchIds) { try { await Promise.all(matchIds.map(async matchId => { const response = await fetch(`https://www.managerzone.com/xml/match_info.php?sport_id=${this.sportId}&match_id=${matchId}`); const xmlDoc = new DOMParser().parseFromString(await response.text(), "text/xml"); const teamElements = Array.from(xmlDoc.getElementsByTagName("Team")); const ourTeamElement = teamElements.find(team => team.getAttribute("id") === this.teamId); this.updatePlayerAppearances(ourTeamElement); })); this.displayPlayerMatches(); } catch (error) { console.warn("Error fetching match info:", error); } } updatePlayerAppearances(ourTeamElement) { Array.from(ourTeamElement.getElementsByTagName("Player")).forEach(player => { const playerId = player.getAttribute("id"); const playerName = player.getAttribute("name"); const playerInfo = this.appearances.get(playerId); if (playerInfo) { playerInfo.appearances += 1; } else { this.appearances.set(playerId, { name: playerName, appearances: 1 }); } }); } displayPlayerMatches() { this.loadingDiv.style.display = "none"; this.table.innerHTML = ""; this.table.appendChild(this.createHeaderRow()); Array.from(this.appearances) .sort((a, b) => b[1].appearances - a[1].appearances) .forEach(([playerId, playerInfo]) => { this.table.appendChild(this.createPlayerRow(playerId, playerInfo)); }); } createHeaderRow() { const row = document.createElement("tr"); [UI_TEXT.PLAYER_COLUMN, UI_TEXT.GAMES_COLUMN].forEach(text => { const th = document.createElement("th"); th.className = "friendly-header"; th.textContent = text; row.appendChild(th); }); return row; } createPlayerRow(playerId, playerInfo) { const row = document.createElement("tr"); const nameCell = document.createElement("td"); nameCell.className = "friendly-cell"; const link = document.createElement("a"); link.className = "friendly-link"; link.href = `https://www.managerzone.com/?p=players&pid=${playerId}`; link.textContent = playerInfo.name; nameCell.appendChild(link); const appearancesCell = document.createElement("td"); appearancesCell.className = "friendly-cell"; appearancesCell.textContent = playerInfo.appearances; row.appendChild(nameCell); row.appendChild(appearancesCell); return row; } showNoMatchesMessage() { this.loadingMessage.style.color = "lightgray"; this.loadingMessage.textContent = UI_TEXT.NO_MATCHES_TEXT; } } new FriendlyMatchTracker(); })();