// ==UserScript== // @name MZ - Unlucky // @namespace douglaskampl // @version 2.727 // @description Finds unlucky teams // @author Douglas // @match https://www.managerzone.com/?p=league&type* // @grant GM_addStyle // @run-at document-idle // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/534000/MZ%20-%20Unlucky.user.js // @updateURL https://update.greasyfork.icu/scripts/534000/MZ%20-%20Unlucky.meta.js // ==/UserScript== (function () { 'use strict'; const DEBUG = false; const BATCH_SIZE = 5; const MAX_GK_LOOKUP_ATTEMPTS = 10; GM_addStyle(`@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); @keyframes textGlitch { 0% { transform: translate(0); text-shadow: 0 0 8px rgba(255, 106, 193, 0.8); } 25% { text-shadow: -1px 1px 8px rgba(22, 242, 242, 0.8), 1px -1px 8px rgba(255, 106, 193, 0.8); } 50% { text-shadow: 1px -1px 8px rgba(22, 242, 242, 0.8), -1px 1px 8px rgba(255, 106, 193, 0.8); } 75% { text-shadow: -1px 0 8px rgba(22, 242, 242, 0.8), 1px 0 8px rgba(255, 106, 193, 0.8); } 100% { transform: translate(0); text-shadow: 0 0 8px rgba(255, 106, 193, 0.8); } } .pulse-dot { display: inline-block; width: 8px; height: 8px; background-color: #ff6ac1; border-radius: 50%; margin-right: 10px; animation: pulse 1.5s infinite ease-in-out; } @keyframes pulse { 0% { transform: scale(0.8); opacity: 0.5; } 50% { transform: scale(1.2); opacity: 1; } 100% { transform: scale(0.8); opacity: 0.5; } } @keyframes modalFadeIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } @keyframes glow { 0% { box-shadow: 0 0 5px rgba(255, 0, 255, 0.5); } 50% { box-shadow: 0 0 20px rgba(0, 255, 255, 0.8); } 100% { box-shadow: 0 0 5px rgba(255, 0, 255, 0.5); } } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } #unluckyModal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); backdrop-filter: blur(5px); display: flex; justify-content: center; align-items: center; z-index: 9999; opacity: 0; animation: modalFadeIn 0.3s ease-out forwards; font-size: 16px; font-family: 'Inter', sans-serif; } #unluckyModalContent { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); background-size: 200% 200%; animation: gradientShift 15s ease infinite; padding: 25px; border-radius: 10px; width: 700px; max-width: 90vw; max-height: 85vh; overflow-y: auto; box-shadow: 0 0 30px rgba(138, 43, 226, 0.6); color: #fff; border: 1px solid rgba(255, 255, 255, 0.1); transform: translateY(20px); transition: transform 0.3s ease-out; box-sizing: border-box; } #unluckyModal:hover #unluckyModalContent { transform: translateY(0); } #unluckyModalHeader { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 1px solid rgba(255, 105, 180, 0.3); padding-bottom: 10px; } #unluckyModalTitle { font-size: 24px; font-weight: bold; color: #ff6ac1; text-shadow: 0 0 10px rgba(255, 105, 180, 0.7); font-family: 'Orbitron', sans-serif; letter-spacing: 2px; text-transform: uppercase; } #unluckyModalClose { cursor: pointer; font-size: 24px; color: #16f2f2; transition: all 0.2s; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border-radius: 50%; } #unluckyModalClose:hover { color: #ff6ac1; transform: rotate(90deg); background-color: rgba(255, 255, 255, 0.1); } .unluckyOption { margin: 15px 0; padding: 12px 20px; width: 100%; box-sizing: border-box; text-align: center; background: linear-gradient(to right, #614385, #516395); border: none; border-radius: 5px; cursor: pointer; color: white; font-weight: 500; font-size: 17px; transition: all 0.3s ease; position: relative; overflow: hidden; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); max-width: 100%; font-family: 'Inter', sans-serif; } .unluckyOption:before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: 0.5s; } .unluckyOption:hover { transform: translateY(-3px); box-shadow: 0 7px 14px rgba(0, 0, 0, 0.4); animation: glow 1.5s infinite; } .unluckyOption:hover:before { left: 100%; } .unluckyOption:active { transform: translateY(1px); } #unluckyResults { margin-top: 20px; max-height: 550px; overflow-y: auto; padding: 15px; border: 1px solid rgba(85, 213, 219, 0.3); display: none; background-color: rgba(0, 0, 0, 0.3); border-radius: 5px; color: #f0f0f0; font-family: 'Inter', sans-serif; transition: all 0.3s ease; } #unluckyResults p { margin: 5px 0; line-height: 1.5; } #unluckyResults::-webkit-scrollbar { width: 8px; } #unluckyResults::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.2); border-radius: 10px; } #unluckyResults::-webkit-scrollbar-thumb { background: linear-gradient(180deg, #ff6ac1, #7a4feb); border-radius: 10px; } #leftmenu_unlucky a { transition: all 0.3s ease; display: inline-block; font-family: 'Inter', sans-serif; } #leftmenu_unlucky a:hover { color: #ff6ac1 !important; text-shadow: 0 0 5px rgba(255, 105, 180, 0.7); transform: translateX(3px); } .team-stats { margin-bottom: 12px; padding: 10px; border-radius: 4px; border-left: 3px solid #ff6ac1; background-color: rgba(255, 255, 255, 0.05); font-size: 15px; font-family: 'Inter', sans-serif; } .stat-card { margin-bottom: 15px; padding: 15px; border-radius: 8px; background-color: rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgba(138, 43, 226, 0.3); font-family: 'Inter', sans-serif; } .stat-card-title { margin-bottom: 10px; padding-bottom: 8px; font-size: 19px; font-weight: bold; color: #16f2f2; border-bottom: 1px solid rgba(255, 106, 193, 0.5); } .stat-item { margin: 10px 0; padding: 10px; border-radius: 4px; display: flex; align-items: center; justify-content: space-between; background-color: rgba(255, 255, 255, 0.05); font-size: 15px; flex-wrap: wrap; } .stat-item:hover { background-color: rgba(255, 255, 255, 0.1); } .stat-value { font-weight: bold; color: #ff6ac1; margin-left: auto; padding-left: 10px; flex-shrink: 0; } .stat-rank { display: inline-block; width: 24px; height: 24px; margin-right: 10px; background: linear-gradient(to right, #614385, #516395); border-radius: 50%; text-align: center; line-height: 24px; font-size: 13px; } .back-button { margin-top: 15px; padding: 8px 15px; background: linear-gradient(to right, #516395, #614385); border: none; border-radius: 4px; color: white; cursor: pointer; transition: all 0.3s ease; font-size: 15px; font-family: 'Inter', sans-serif; } .back-button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } .pagination { display: flex; justify-content: center; margin-top: 15px; } .pagination-button { padding: 6px 12px; margin: 0 5px; border: none; border-radius: 4px; background: linear-gradient(to right, #516395, #614385); color: white; cursor: pointer; transition: all 0.3s ease; font-family: 'Inter', sans-serif; } .pagination-button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } .pagination-button.active { background: linear-gradient(to right, #ff6ac1, #ff6ac1); } .league-selector { padding: 10px; margin-bottom: 10px; background-color: rgba(0, 0, 0, 0.2); border-radius: 5px; } .league-selector-title { margin-bottom: 10px; color: #16f2f2; font-size: 17px; } .league-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; } .league-item { padding: 5px 8px; text-align: center; background-color: rgba(255, 255, 255, 0.1); border-radius: 4px; cursor: pointer; transition: all 0.2s; font-size: 15px; display: flex; align-items: center; justify-content: center; } .league-item:hover { background-color: rgba(255, 106, 193, 0.3); } .league-item.active { background-color: rgba(255, 106, 193, 0.5); } .tab-container { display: flex; margin-bottom: 15px; } .tab { padding: 10px 20px; background: rgba(255, 255, 255, 0.1); border: none; color: white; cursor: pointer; transition: all 0.3s ease; font-size: 16px; font-family: 'Inter', sans-serif; } .tab:first-child { border-radius: 5px 0 0 5px; } .tab:last-child { border-radius: 0 5px 5px 0; } .tab.active { background: linear-gradient(to right, #ff6ac1, #7a4feb); } .tab-content { display: none; } .tab-content.active { display: block; } .toggle-matches { cursor: pointer; color: #16f2f2; text-decoration: underline; margin-left: 5px; font-size: 0.95em; } .toggle-matches:hover { color: #ff6ac1; } .match-list { display: none; margin-top: 10px; padding: 8px; background-color: rgba(0, 0, 0, 0.2); border-radius: 5px; } .match-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; margin-bottom: 5px; border-radius: 3px; background-color: rgba(255, 255, 255, 0.05); transition: all 0.2s; font-size: 14px; } .match-item:hover { background-color: rgba(255, 255, 255, 0.1); } .match-link { color: #fff; text-decoration: none; flex-grow: 1; } .match-link:hover { color: #ff6ac1; } .match-result { font-weight: bold; margin-left: 10px; } .match-result.win { color: #2ecc71; } .match-result.draw { color: #f39c12; } .match-result.loss { color: #e74c3c; } .match-stats { font-size: 0.9em; color: #bbb; } .info-icon { position: fixed; bottom: 20px; right: 20px; width: 40px; height: 40px; background-color: rgba(22, 242, 242, 0.8); color: #1a1a2e; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; box-shadow: 0 0 15px rgba(22, 242, 242, 0.5); z-index: 10000; transition: all 0.3s ease; } .info-icon:hover { background-color: rgba(255, 106, 193, 0.8); box-shadow: 0 0 15px rgba(255, 106, 193, 0.5); transform: scale(1.1); } .info-tooltip { position: fixed; bottom: 70px; right: 20px; width: 350px; max-height: 70vh; overflow-y: auto; padding: 15px; background-color: rgba(26, 26, 46, 0.95); border: 1px solid rgba(22, 242, 242, 0.5); border-radius: 10px; color: white; font-size: 14px; line-height: 1.5; z-index: 10000; display: none; box-shadow: 0 0 20px rgba(22, 242, 242, 0.3); max-width: 80vw; font-family: 'Inter', sans-serif; } .info-tooltip h3 { color: #ff6ac1; margin-top: 0; margin-bottom: 10px; border-bottom: 1px solid rgba(255, 106, 193, 0.3); padding-bottom: 5px; font-family: 'Orbitron', sans-serif; } .info-tooltip p { margin: 10px 0; } .info-tooltip .formula { background-color: rgba(0, 0, 0, 0.2); padding: 8px; border-radius: 5px; margin: 10px 0; border-left: 3px solid #16f2f2; font-family: 'Courier New', monospace; } .info-tooltip .formula-explanation { margin-left: 15px; margin-bottom: 15px; color: #ddd; } .league-link { color: #16f2f2; text-decoration: none; transition: all 0.2s; display: inline-flex; align-items: center; } .league-link:hover { color: #ff6ac1; text-decoration: none; } .league-link:hover .league-label { background-color: rgba(255, 106, 193, 0.4); border-color: rgba(255, 106, 193, 0.7); } .loading-stage { margin-left: 10px; color: #ff6ac1; font-style: italic; font-size: 0.9em; } .loading-progress { margin-left: 10px; color: #16f2f2; } .league-range-input { display: flex; margin: 15px 0; gap: 10px; align-items: center; } .league-range-input input { flex: 1; padding: 8px; border-radius: 4px; border: none; background-color: rgba(255, 255, 255, 0.1); color: white; outline: none; } .league-input { width: 100%; padding: 10px; border-radius: 4px; margin-bottom: 15px; border: none; background-color: rgba(255, 255, 255, 0.1); color: white; outline: none; font-family: 'Inter', sans-serif; } .league-entry-container { margin-bottom: 20px; } .league-entry-form { display: flex; gap: 10px; margin-bottom: 10px; align-items: center; } .league-entry-form input, .league-entry-form select { flex: 1; padding: 8px 12px; border: none; border-radius: 4px; background-color: rgba(255, 255, 255, 0.1); color: lightgray; outline: none; } .league-entry-form select { cursor: pointer; } .league-entry-form .add-button { width: 36px; height: 36px; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #614385, #516395); border: none; border-radius: 50%; color: white; font-size: 20px; cursor: pointer; transition: all 0.3s ease; flex-shrink: 0; } .league-entry-form .add-button:hover { transform: scale(1.1); box-shadow: 0 0 10px rgba(138, 43, 226, 0.5); } .league-list { max-height: 200px; overflow-y: auto; padding: 10px; background-color: rgba(0, 0, 0, 0.2); border-radius: 5px; margin-bottom: 15px; } .league-list-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; margin-bottom: 6px; background-color: rgba(255, 255, 255, 0.05); border-radius: 4px; } .league-list-item:last-child { margin-bottom: 0; } .league-list-item .remove-button { background: none; border: none; color: #ff6ac1; cursor: pointer; font-size: 16px; transition: all 0.2s; } .league-list-item .remove-button:hover { transform: scale(1.2); } .league-label { background-color: rgba(22, 242, 242, 0.15); border: 1px solid rgba(22, 242, 242, 0.4); color: #e0e0e0; padding: 2px 8px; border-radius: 4px; font-size: 0.85em; font-weight: 500; margin-left: 6px; white-space: nowrap; transition: all 0.2s; display: inline-block; }`); const CURRENCIES = { "R$": 2.62589, EUR: 9.1775, USD: 7.4234, "点": 1, SEK: 1, NOK: 1.07245, DKK: 1.23522, GBP: 13.35247, CHF: 5.86737, RUB: 0.26313, CAD: 5.70899, AUD: 5.66999, MZ: 1, MM: 1, PLN: 1.95278, ILS: 1.6953, INR: 0.17, THB: 0.17079, ZAR: 1.23733, SKK: 0.24946, BGN: 4.70738, MXN: 0.68576, ARS: 2.64445, BOB: 0.939, UYU: 0.256963, PYG: 0.001309, ISK: 0.10433, SIT: 0.03896, JPY: 0.06, }; const LOG_COLORS = { info: "#16f2f2", warn: "#ff6ac1", error: "#ff0000", success: "#00ff00", debug: "#f39c12", gk: "#7a4feb" }; const LEAGUE_TYPES = [ { value: "senior", label: "Senior" }, { value: "u23", label: "U23" }, { value: "u23_world", label: "U23 World" }, { value: "u21", label: "U21" }, { value: "u21_world", label: "U21 World" }, { value: "u18", label: "U18" }, { value: "u18_world", label: "U18 World" } ]; const REGIONAL_LEAGUE_NAMES = { 727: "Americas", 1: "Argentina", 122: "Brazil", 848: "Central Europe", 969: "Iberia", 1090: "Mediterranean", 1211: "Northern Europe", 243: "Poland", 364: "Romania", 485: "Sweden", 606: "Turkey", 1332: "World" }; const teamPlayersCache = {}; const teamGoalkeeperCache = {}; const xmlCache = {}; const matchCache = {}; const gkLogging = { attempts: 0, successes: 0, failures: 0, reasons: {}, teamDetails: {}, conversionDetails: {}, processedTeams: new Set(), teamsWithGk: new Set(), matchesUsed: new Set() }; function log(msg, type = "info", obj = null) { if (!DEBUG) return; const style = `color: ${LOG_COLORS[type] || LOG_COLORS.info}; font-weight: bold;`; if (obj !== null) { console.log(`%c[MZ-UNLUCKY] ${msg}`, style, obj); } else { console.log(`%c[MZ-UNLUCKY] ${msg}`, style); } } function displayGkDebugInfo() { log("===== GOALKEEPER DEBUGGING INFORMATION =====", "gk"); log(`Total attempts: ${gkLogging.attempts}`, "gk"); log(`Successes: ${gkLogging.successes}`, "gk"); log(`Failures: ${gkLogging.failures}`, "gk"); log(`Success rate: ${((gkLogging.successes / Math.max(gkLogging.attempts, 1)) * 100).toFixed(2)}%`, "gk"); log(`Teams processed: ${gkLogging.processedTeams.size}`, "gk"); log(`Teams with goalkeeper data: ${gkLogging.teamsWithGk.size}`, "gk"); log(`Total matches used: ${gkLogging.matchesUsed.size}`, "gk"); log("Failure reasons:", "gk", gkLogging.reasons); log("Team details:", "gk", gkLogging.teamDetails); log("Currency conversion details:", "gk", gkLogging.conversionDetails); const currencyCount = {}; for (const teamId in gkLogging.teamDetails) { const details = gkLogging.teamDetails[teamId]; if (details.success && details.currency) { currencyCount[details.currency] = (currencyCount[details.currency] || 0) + 1; } } log("GKs by currency:", "gk", currencyCount); const currencyAvg = {}; for (const teamId in gkLogging.teamDetails) { const details = gkLogging.teamDetails[teamId]; if (details.success && details.currency) { if (!currencyAvg[details.currency]) { currencyAvg[details.currency] = { count: 0, total: 0, totalUsd: 0 }; } currencyAvg[details.currency].count++; currencyAvg[details.currency].total += details.originalValue; currencyAvg[details.currency].totalUsd += details.valueInUsd; } } for (const currency in currencyAvg) { const data = currencyAvg[currency]; data.average = data.total / data.count; data.averageUsd = data.totalUsd / data.count; } log("Average GK values by currency:", "gk", currencyAvg); const topGks = Object.entries(gkLogging.teamDetails) .filter(([_, details]) => details.success) .sort((a, b) => b[1].valueInUsd - a[1].valueInUsd) .slice(0, 5); log("Top 5 most valuable goalkeepers:", "gk", topGks); log("================================================", "gk"); } function getCurrentLeagueId() { const url = window.location.href; const match = url.match(/sid=(\d+)/); return match ? match[1] : null; } function getCurrentLeagueType() { const url = window.location.href; const match = url.match(/type=([^&]+)/); return match ? match[1] : null; } function getDivisionDisplayName(sid, leagueType) { const sidNum = parseInt(sid); if (!sidNum) return `League ${sid}`; if (leagueType && leagueType.includes('world')) { if (sidNum === 1) return "Top Series"; let level = 0; let levelStartSid = 1; let leaguesInLevel = 1; while (sidNum >= levelStartSid + leaguesInLevel) { levelStartSid += leaguesInLevel; level++; leaguesInLevel *= 3; } if (level > 0) { const indexInLevel = sidNum - levelStartSid + 1; return `Div ${level}.${indexInLevel}`; } } else { const regionalName = REGIONAL_LEAGUE_NAMES[sidNum]; if (regionalName) { return regionalName; } } return `League ${sid}`; } function makeRequest(url) { log(`Making request to: ${url}`, "debug"); return fetch(url) .then(response => { if (!response.ok) { log(`Request failed with status ${response.status}`, "error"); throw new Error(`Request failed with status ${response.status}`); } return response.text(); }); } function convertToUsd(value, currency) { gkLogging.conversionDetails[currency] = gkLogging.conversionDetails[currency] || []; log(`Converting value from ${currency}: ${value}`, "debug"); if (currency === 'USD') { log(`No conversion needed for USD value: ${value}`, "gk"); gkLogging.conversionDetails[currency].push({ original: value, converted: value, rate: 1, formula: 'No conversion (USD)' }); return value; } const conversionRate = CURRENCIES[currency] || 1; if (!CURRENCIES[currency]) { log(`Unknown currency: ${currency}, defaulting rate to 1`, "warn"); } let valueInUsd; if (currency === 'SEK') { valueInUsd = (value / CURRENCIES.USD); log(`Converting from SEK: ${value} SEK = ${valueInUsd} USD (${value} / ${CURRENCIES.USD})`, "gk"); } else { const valueInSek = value * conversionRate; valueInUsd = valueInSek / CURRENCIES.USD; log(`Converting from ${currency}: ${value} ${currency} = ${valueInSek} SEK = ${valueInUsd} USD (${value} * ${conversionRate} / ${CURRENCIES.USD})`, "gk"); } gkLogging.conversionDetails[currency].push({ original: value, converted: valueInUsd, rate: conversionRate, usdRate: CURRENCIES.USD, formula: `(${value} * ${conversionRate}) / ${CURRENCIES.USD} = ${valueInUsd}` }); return valueInUsd; } function createModal() { const modal = document.createElement('div'); modal.id = 'unluckyModal'; modal.style.display = 'none'; const modalContent = document.createElement('div'); modalContent.id = 'unluckyModalContent'; const modalHeader = document.createElement('div'); modalHeader.id = 'unluckyModalHeader'; const modalTitle = document.createElement('div'); modalTitle.id = 'unluckyModalTitle'; modalTitle.innerHTML = 'アンラッキー 運命'; const modalClose = document.createElement('div'); modalClose.id = 'unluckyModalClose'; modalClose.textContent = '×'; modalClose.addEventListener('click', closeModal); modalHeader.appendChild(modalTitle); modalHeader.appendChild(modalClose); const currentOption = document.createElement('div'); currentOption.className = 'unluckyOption'; currentOption.innerHTML = '🔍 Current League'; currentOption.addEventListener('click', function() { findUnluckyTeams('current'); }); const specificOption = document.createElement('div'); specificOption.className = 'unluckyOption'; specificOption.innerHTML = '🎯 Specific League'; specificOption.addEventListener('click', function() { findUnluckyTeams('specific'); }); const allOption = document.createElement('div'); allOption.className = 'unluckyOption'; allOption.innerHTML = '🌐 All Leagues'; allOption.addEventListener('click', function() { findUnluckyTeams('all'); }); const resultsDiv = document.createElement('div'); resultsDiv.id = 'unluckyResults'; modalContent.appendChild(modalHeader); modalContent.appendChild(currentOption); modalContent.appendChild(specificOption); modalContent.appendChild(allOption); modalContent.appendChild(resultsDiv); modal.appendChild(modalContent); const infoIcon = document.createElement('div'); infoIcon.className = 'info-icon'; infoIcon.textContent = 'ℹ️'; infoIcon.title = 'Click for information about luck calculations'; const infoTooltip = document.createElement('div'); infoTooltip.className = 'info-tooltip'; infoTooltip.innerHTML = `
The Luck Index combines multiple factors to accurately measure how lucky or unlucky a team has been based on their match performance data:
Offensive Conversion Rate: (Goals Scored ÷ Shots on Target) × 100
Defensive Conversion Rate: (Goals Conceded ÷ Shots on Target Against) × 100
GK Value Adjustment: min(GK Value in USD ÷ 1,000,000, 5) × 0.5
A higher Luck Index indicates a luckier team (scoring from relatively few shots and/or conceding few goals despite facing many shots on target).
A lower Luck Index indicates an unlucky team (struggling to score despite creating chances and/or conceding frequently from relatively few shots).
The GK Value Adjustment factor accounts for goalkeeper quality. Teams with expensive goalkeepers are expected to have better defensive conversion rates, so this reduces their luck rating (as good defensive performance with a top goalkeeper is skill, not luck).
Additional metrics tracked:
Example calculation:
Team A has scored 15 goals from 50 shots on target (30% offensive conversion)
They've conceded 10 goals from 40 shots on target against (25% defensive conversion)
Their goalkeeper is worth $3M
GK Value Adjustment: min(3, 5) × 0.5 = 1.5
Luck Index = 30% - 25% - 1.5 = 3.5
Unlucky ☯ |
Error: ${errorMsg}
`; showBackButton(resultsDiv); } return; } } const tableUrl = `https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${leagueId}&tid=1&sport=soccer&sub=table`; const scheduleUrl = `https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${leagueId}&tid=1&sport=soccer&sub=schedule`; const loadingEl = document.createElement('div'); loadingEl.style.display = 'flex'; loadingEl.style.justifyContent = 'center'; loadingEl.style.alignItems = 'center'; loadingEl.style.margin = '30px 0'; loadingEl.innerHTML = ` Loading league data...`; if (resultsDiv) { resultsDiv.innerHTML = ''; resultsDiv.appendChild(loadingEl); } try { loadingEl.innerHTML = ` Loading league data Step 1/3: Fetching league information`; log(`Processing league ID: ${leagueId} (Type: ${leagueType})`, "info"); const [tableHTML, scheduleHTML] = await Promise.all([makeRequest(tableUrl), makeRequest(scheduleUrl)]); loadingEl.innerHTML = ` Processing league data Step 2/3: Processing teams and schedule`; const teams = extractTeamData(tableHTML); const allMatches = extractScheduleData(scheduleHTML, teams); const playedMatches = allMatches.filter(match => /^\d+\s*-\s*\d+$/.test(match.result)); log(`Found ${teams.length} teams and ${playedMatches.length} played matches in league ${leagueId}`, "info"); const teamStats = {}; teams.forEach(team => { teamStats[team.id] = { name: team.name, shotsOnTarget: 0, goalsScored: 0, shotsOnTargetReceived: 0, goalsConceded: 0, matchesPlayed: 0, unluckyMatches: 0, dominatingMatches: 0, luckyWins: 0, outshot: 0, unluckyMatchDetails: [], luckyMatchDetails: [], goalkeeper: null, players18Count: 0 }; }); if (playedMatches.length > 0) { gkLogging.processedTeams.clear(); gkLogging.teamsWithGk.clear(); gkLogging.matchesUsed.clear(); loadingEl.innerHTML = ` Analyzing match data Step 3/3: Processing matches (0/${playedMatches.length})`; const teamIdMap = {}; teams.forEach(team => { teamIdMap[team.id] = team; }); const batchSize = BATCH_SIZE; const maxMatches = playedMatches.length; for (let i = 0; i < maxMatches; i += batchSize) { const batch = playedMatches.slice(i, i + batchSize); const matchPromises = batch.map(match => processMatchComplete(match.mid, teamIdMap)); const matchResults = await Promise.all(matchPromises); if (i < MAX_GK_LOOKUP_ATTEMPTS * batchSize) { const gkPromises = matchResults.filter(Boolean).map(matchData => extractGoalkeeperData(matchData, teamIdMap)); await Promise.all(gkPromises); } matchResults.forEach(matchData => { if (!matchData) return; if (teamStats[matchData.homeTeam.id]) { const homeStats = teamStats[matchData.homeTeam.id]; homeStats.shotsOnTarget += matchData.homeTeam.shotsOnTarget; homeStats.goalsScored += matchData.homeTeam.goals; homeStats.shotsOnTargetReceived += matchData.awayTeam.shotsOnTarget; homeStats.goalsConceded += matchData.awayTeam.goals; homeStats.matchesPlayed++; if (matchData.homeTeam.shotsOnTarget > matchData.awayTeam.shotsOnTarget) { homeStats.dominatingMatches++; if (matchData.homeTeam.result !== 'W') { homeStats.unluckyMatches++; homeStats.unluckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.awayTeam.name, homeTeam: true, result: matchData.homeTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } if (matchData.homeTeam.shotsOnTarget < matchData.awayTeam.shotsOnTarget) { homeStats.outshot++; if (matchData.homeTeam.result === 'W') { homeStats.luckyWins++; homeStats.luckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.awayTeam.name, homeTeam: true, result: matchData.homeTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } } if (teamStats[matchData.awayTeam.id]) { const awayStats = teamStats[matchData.awayTeam.id]; awayStats.shotsOnTarget += matchData.awayTeam.shotsOnTarget; awayStats.goalsScored += matchData.awayTeam.goals; awayStats.shotsOnTargetReceived += matchData.homeTeam.shotsOnTarget; awayStats.goalsConceded += matchData.homeTeam.goals; awayStats.matchesPlayed++; if (matchData.awayTeam.shotsOnTarget > matchData.homeTeam.shotsOnTarget) { awayStats.dominatingMatches++; if (matchData.awayTeam.result !== 'W') { awayStats.unluckyMatches++; awayStats.unluckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.homeTeam.name, homeTeam: false, result: matchData.awayTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } if (matchData.awayTeam.shotsOnTarget < matchData.homeTeam.shotsOnTarget) { awayStats.outshot++; if (matchData.awayTeam.result === 'W') { awayStats.luckyWins++; awayStats.luckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.homeTeam.name, homeTeam: false, result: matchData.awayTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } } }); loadingEl.innerHTML = ` Analyzing match data Step 3/3: Processing matches (${Math.min(i + batch.length, maxMatches)}/${maxMatches}) (Found: ${gkLogging.teamsWithGk.size}/${teams.length} goalkeepers)`; } teams.forEach(team => { if (teamGoalkeeperCache[team.id] && teamStats[team.id]) { teamStats[team.id].goalkeeper = teamGoalkeeperCache[team.id]; log(`Added goalkeeper data for team ${team.name} (${team.id})`, "debug"); } else { log(`No goalkeeper data found for team ${team.name} (${team.id})`, "debug"); } if (teamPlayersCache[team.id] && teamStats[team.id]) { teamStats[team.id].players18Count = teamPlayersCache[team.id].players18Count || 0; log(`Added 18-year-old player count for team ${team.name} (${team.id}): ${teamStats[team.id].players18Count}`, "debug"); } }); log(`Goalkeeper data coverage: ${gkLogging.teamsWithGk.size}/${teams.length} teams (${((gkLogging.teamsWithGk.size / teams.length) * 100).toFixed(1)}%)`, gkLogging.teamsWithGk.size > 0 ? "success" : "warn"); } const validTeams = []; teams.forEach(team => { const stats = teamStats[team.id] || { shotsOnTarget: 0, goalsScored: 0, shotsOnTargetReceived: 0, goalsConceded: 0, matchesPlayed: 0, unluckyMatches: 0, dominatingMatches: 0, luckyWins: 0, outshot: 0, unluckyMatchDetails: [], luckyMatchDetails: [], goalkeeper: null, players18Count: 0 }; if (stats.shotsOnTarget === 0 || stats.shotsOnTargetReceived === 0) { log(`Excluding team ${team.name} (${team.id}) - Has 0 shots on target (for: ${stats.shotsOnTarget}, against: ${stats.shotsOnTargetReceived})`, "warn"); return; } team.shotsOnTarget = stats.shotsOnTarget; team.goalsScored = stats.goalsScored; team.shotsOnTargetReceived = stats.shotsOnTargetReceived; team.goalsConceded = stats.goalsConceded; team.matchesPlayed = stats.matchesPlayed; team.unluckyMatches = stats.unluckyMatches; team.dominatingMatches = stats.dominatingMatches; team.luckyWins = stats.luckyWins; team.outshot = stats.outshot; team.unluckyMatchDetails = stats.unluckyMatchDetails; team.luckyMatchDetails = stats.luckyMatchDetails; team.goalkeeper = stats.goalkeeper; team.players18Count = stats.players18Count; team.offensiveConversionRate = stats.shotsOnTarget > 0 ? (stats.goalsScored / stats.shotsOnTarget * 100).toFixed(1) : '0.0'; team.defensiveConversionRate = stats.shotsOnTargetReceived > 0 ? (stats.goalsConceded / stats.shotsOnTargetReceived * 100).toFixed(1) : '0.0'; let luckIndex = parseFloat(team.offensiveConversionRate) - parseFloat(team.defensiveConversionRate); if (team.goalkeeper && team.goalkeeper.valueInUsd) { const gkValueFactor = Math.min(team.goalkeeper.valueInUsd / 1000000, 5) * 0.5; luckIndex -= gkValueFactor; log(`Team ${team.name} GK adjustment: ${team.goalkeeper.valueInUsd.toFixed(2)} USD = -${gkValueFactor.toFixed(1)} luck points`, "gk"); } else { log(`No goalkeeper data for team ${team.name}`, "warn"); } team.luckIndex = luckIndex.toFixed(1); team.unluckyIndex = stats.dominatingMatches > 0 ? ((stats.unluckyMatches / stats.dominatingMatches) * 100).toFixed(1) : '0.0'; team.luckyWinPct = stats.outshot > 0 ? ((stats.luckyWins / stats.outshot) * 100).toFixed(1) : '0.0'; if (stats.dominatingMatches > 0) { const unluckyPct = stats.unluckyMatches / stats.dominatingMatches; const sampleWeight = 1 + Math.log(Math.max(stats.dominatingMatches, 1)) / 10; team.weightedUnluckyScore = (unluckyPct * sampleWeight * 100).toFixed(1); } else { team.weightedUnluckyScore = '0.0'; } if (stats.outshot > 0) { const luckyPct = stats.luckyWins / stats.outshot; const sampleWeight = 1 + Math.log(Math.max(stats.outshot, 1)) / 10; team.weightedLuckyScore = (luckyPct * sampleWeight * 100).toFixed(1); } else { team.weightedLuckyScore = '0.0'; } validTeams.push(team); }); log(`Filtered teams: ${validTeams.length} of ${teams.length} teams have valid shot data`, "info"); const statLeaders = { bestOffensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.offensiveConversionRate) - parseFloat(a.offensiveConversionRate)).slice(0, 3), worstOffensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.offensiveConversionRate) - parseFloat(b.offensiveConversionRate)).slice(0, 3), bestDefensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.defensiveConversionRate) - parseFloat(b.defensiveConversionRate)).slice(0, 3), worstDefensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.defensiveConversionRate) - parseFloat(a.defensiveConversionRate)).slice(0, 3), luckiest: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.luckIndex) - parseFloat(a.luckIndex)).slice(0, 3), unluckiest: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.luckIndex) - parseFloat(b.luckIndex)).slice(0, 3), mostUnluckyMatches: validTeams.filter(team => team.dominatingMatches > 0).sort((a, b) => parseFloat(b.weightedUnluckyScore) - parseFloat(a.weightedUnluckyScore)).slice(0, 3), mostLuckyWins: validTeams.filter(team => team.outshot > 0).sort((a, b) => parseFloat(b.weightedLuckyScore) - parseFloat(a.weightedLuckyScore)).slice(0, 3) }; displayGkDebugInfo(); if (allLeaguesData !== null) { allLeaguesData[leagueId] = { teams: validTeams, statLeaders, leagueType }; updateGlobalLeaders(allLeaguesData); updateLeagueSelector(allLeaguesData, resultsDiv, leagueId); } else { displayLeagueData(validTeams, statLeaders, leagueId, leagueType, resultsDiv); } log(`League ${leagueId} processed successfully`, "success"); } catch (error) { log(`Error processing league ${leagueId}: ${error.message}`, "error"); if (resultsDiv) { resultsDiv.innerHTML = `Error: Failed to process league data: ${error.message}
`; showBackButton(resultsDiv); } } } function updateGlobalLeaders(allLeaguesData) { const allTeams = []; for (const leagueId in allLeaguesData) { if (leagueId === 'globalLeaders') continue; allLeaguesData[leagueId].teams.forEach(team => { team.leagueId = leagueId; team.leagueType = allLeaguesData[leagueId].leagueType; allTeams.push(team); }); } const globalLeaders = { bestOffensiveConversion: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.offensiveConversionRate) - parseFloat(a.offensiveConversionRate)).slice(0, 5), worstOffensiveConversion: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.offensiveConversionRate) - parseFloat(b.offensiveConversionRate)).slice(0, 5), bestDefensiveConversion: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.defensiveConversionRate) - parseFloat(b.defensiveConversionRate)).slice(0, 5), worstDefensiveConversion: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.defensiveConversionRate) - parseFloat(a.defensiveConversionRate)).slice(0, 5), luckiest: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.luckIndex) - parseFloat(a.luckIndex)).slice(0, 5), unluckiest: allTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.luckIndex) - parseFloat(b.luckIndex)).slice(0, 5), mostUnluckyMatches: allTeams.filter(team => team.dominatingMatches > 0).sort((a, b) => parseFloat(b.weightedUnluckyScore) - parseFloat(a.weightedUnluckyScore)).slice(0, 5), mostLuckyWins: allTeams.filter(team => team.outshot > 0).sort((a, b) => parseFloat(b.weightedLuckyScore) - parseFloat(a.weightedLuckyScore)).slice(0, 5) }; allLeaguesData.globalLeaders = globalLeaders; log("Global leaders calculated", "success"); } function displayLeagueData(teams, statLeaders, leagueId, leagueType, resultsDiv) { const contentDiv = document.createElement('div'); const tabContainer = document.createElement('div'); tabContainer.className = 'tab-container'; const summaryTab = document.createElement('button'); summaryTab.className = 'tab active'; summaryTab.textContent = 'Statistics Summary'; summaryTab.addEventListener('click', () => activateTab('summary')); const teamsTab = document.createElement('button'); teamsTab.className = 'tab'; teamsTab.textContent = 'All Teams'; teamsTab.addEventListener('click', () => activateTab('teams')); tabContainer.appendChild(summaryTab); tabContainer.appendChild(teamsTab); contentDiv.appendChild(tabContainer); const summaryContent = document.createElement('div'); summaryContent.id = 'summary-tab'; summaryContent.className = 'tab-content active'; const teamsContent = document.createElement('div'); teamsContent.id = 'teams-tab'; teamsContent.className = 'tab-content'; const leagueUrl = `https://www.managerzone.com/?p=league&type=${leagueType}&sid=${leagueId}`; const divisionName = getDivisionDisplayName(leagueId, leagueType); const headerInfo = `League: ${divisionName} (ID: ${leagueId})
League Type: ${leagueType}
Teams Found: ${teams.length}
GK Data Coverage: ${teams.filter(t => t.goalkeeper).length}/${teams.length}
No unlucky matches found.
'; } const luckyMatchesDiv = document.createElement('div'); luckyMatchesDiv.className = 'match-list'; luckyMatchesDiv.dataset.teamId = team.id; luckyMatchesDiv.dataset.matchType = 'lucky'; if (team.luckyMatchDetails.length > 0) { team.luckyMatchDetails.forEach(match => { const matchItem = document.createElement('div'); matchItem.className = 'match-item'; const resultClass = match.result === 'W' ? 'win' : (match.result === 'D' ? 'draw' : 'loss'); const matchInfo = match.homeTeam ? `${team.name} vs ${match.opponent}` : `${match.opponent} vs ${team.name}`; matchItem.innerHTML = ` ${matchInfo} SoT: ${match.shotsOnTarget} ${match.score} (${match.result})`; luckyMatchesDiv.appendChild(matchItem); }); } else { luckyMatchesDiv.innerHTML = 'No lucky matches found.
'; } teamDiv.appendChild(unluckyMatchesDiv); teamDiv.appendChild(luckyMatchesDiv); teamsContent.appendChild(teamDiv); }); contentDiv.appendChild(summaryContent); contentDiv.appendChild(teamsContent); function activateTab(tabName) { const tabs = contentDiv.querySelectorAll('.tab'); const contents = contentDiv.querySelectorAll('.tab-content'); tabs.forEach(tab => tab.classList.remove('active')); contents.forEach(content => content.classList.remove('active')); if (tabName === 'summary') { summaryTab.classList.add('active'); summaryContent.classList.add('active'); } else { teamsTab.classList.add('active'); teamsContent.classList.add('active'); } } resultsDiv.innerHTML = ''; resultsDiv.appendChild(contentDiv); document.querySelectorAll('.toggle-matches').forEach(toggle => { toggle.addEventListener('click', function(e) { const teamId = this.dataset.teamId; const matchType = this.dataset.matchType; const parentStatItem = this.closest('.stat-item') || this.closest('.team-stats'); if (!parentStatItem) return; const matchList = parentStatItem.querySelector(`.match-list[data-team-id="${teamId}"][data-match-type="${matchType}"]`); if (matchList) { if (matchList.style.display === 'block') { matchList.style.display = 'none'; this.textContent = "View matches"; } else { matchList.style.display = 'block'; this.textContent = "Hide matches"; } } }); }); } function createStatCard(title, teams, formatter, showRank = false) { const card = document.createElement('div'); card.className = 'stat-card'; const cardTitle = document.createElement('div'); cardTitle.className = 'stat-card-title'; cardTitle.textContent = title; card.appendChild(cardTitle); teams.forEach((team, index) => { const item = document.createElement('div'); item.className = 'stat-item'; let content = ''; if (showRank) { content += `${index + 1} `; } content += formatter(team); const itemContentDiv = document.createElement('div'); itemContentDiv.innerHTML = content; item.appendChild(itemContentDiv); if (team.leagueId && team.leagueType) { const divisionName = getDivisionDisplayName(team.leagueId, team.leagueType); const leagueUrl = `https://www.managerzone.com/?p=league&type=${team.leagueType}&sid=${team.leagueId}`; const leagueInfoDiv = document.createElement('div'); leagueInfoDiv.className = 'stat-value'; leagueInfoDiv.innerHTML = `${divisionName}`; item.appendChild(leagueInfoDiv); } card.appendChild(item); if (itemContentDiv.querySelector('.toggle-matches')) { const toggleElement = itemContentDiv.querySelector('.toggle-matches'); const matchType = toggleElement.dataset.matchType; const matchDetails = matchType === 'unlucky' ? team.unluckyMatchDetails : team.luckyMatchDetails; if (matchDetails && matchDetails.length > 0) { const matchesDiv = document.createElement('div'); matchesDiv.className = 'match-list'; matchesDiv.dataset.teamId = team.id; matchesDiv.dataset.matchType = matchType; matchesDiv.style.display = 'none'; matchesDiv.style.width = '100%'; matchDetails.forEach(match => { const matchItem = document.createElement('div'); matchItem.className = 'match-item'; const resultClass = match.result === 'W' ? 'win' : (match.result === 'D' ? 'draw' : 'loss'); const matchInfo = match.homeTeam ? `${team.name} vs ${match.opponent}` : `${match.opponent} vs ${team.name}`; matchItem.innerHTML = ` ${matchInfo} SoT: ${match.shotsOnTarget} ${match.score} (${match.result})`; matchesDiv.appendChild(matchItem); }); item.appendChild(matchesDiv); } } }); return card; } function updateLeagueSelector(allLeaguesData, resultsDiv, currentLeagueId) { resultsDiv.innerHTML = ''; const tabContainer = document.createElement('div'); tabContainer.className = 'tab-container'; const globalTab = document.createElement('button'); globalTab.className = 'tab active'; globalTab.textContent = 'Global Leaders'; const leagueTab = document.createElement('button'); leagueTab.className = 'tab'; leagueTab.textContent = 'League View'; tabContainer.appendChild(globalTab); tabContainer.appendChild(leagueTab); const globalContent = document.createElement('div'); globalContent.id = 'global-content'; globalContent.className = 'tab-content active'; const leagueContent = document.createElement('div'); leagueContent.id = 'league-content'; leagueContent.className = 'tab-content'; const backButtonContainer = document.createElement('div'); const backButton = document.createElement('button'); backButton.className = 'back-button'; backButton.textContent = '← Back to Options'; backButton.style.marginBottom = '15px'; backButton.addEventListener('click', function() { resultsDiv.style.display = 'none'; resultsDiv.innerHTML = ''; document.querySelectorAll('.unluckyOption').forEach(option => { option.style.display = 'block'; }); }); backButtonContainer.appendChild(backButton); const leagueIds = Object.keys(allLeaguesData) .filter(key => key !== 'globalLeaders') .sort((a, b) => parseInt(a) - parseInt(b)); let currentActiveLeagueIndex = leagueIds.indexOf(currentLeagueId); if (currentActiveLeagueIndex === -1 && leagueIds.length > 0) { currentActiveLeagueIndex = 0; currentLeagueId = leagueIds[0]; } if (allLeaguesData.globalLeaders) { const globalLeaders = allLeaguesData.globalLeaders; const globalSubTabContainer = document.createElement('div'); globalSubTabContainer.className = 'tab-container'; const globalSummaryTab = document.createElement('button'); globalSummaryTab.className = 'tab active'; globalSummaryTab.textContent = 'Statistics Summary'; const globalTeamsTab = document.createElement('button'); globalTeamsTab.className = 'tab'; globalTeamsTab.textContent = 'All Teams'; globalSubTabContainer.appendChild(globalSummaryTab); globalSubTabContainer.appendChild(globalTeamsTab); const globalSummaryContent = document.createElement('div'); globalSummaryContent.id = 'global-summary-tab'; globalSummaryContent.className = 'tab-content active'; const globalTeamsContent = document.createElement('div'); globalTeamsContent.id = 'global-teams-tab'; globalTeamsContent.className = 'tab-content'; const globalHeader = document.createElement('div'); globalHeader.innerHTML = `Showing the best and worst teams across all analyzed leagues
`; globalSummaryContent.appendChild(globalHeader.cloneNode(true)); globalTeamsContent.appendChild(globalHeader.cloneNode(true)); const bestOffensive = createStatCard('Best Offensive Conversion (Global)', globalLeaders.bestOffensiveConversion, team => `${team.name}: ${team.offensiveConversionRate}% (${team.goalsScored}/${team.shotsOnTarget} SoT)${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`, true); const worstOffensive = createStatCard('Worst Offensive Conversion (Global)', globalLeaders.worstOffensiveConversion, team => `${team.name}: ${team.offensiveConversionRate}% (${team.goalsScored}/${team.shotsOnTarget} SoT)${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`, true); const bestDefensive = createStatCard('Best GKs (Global)', globalLeaders.bestDefensiveConversion, team => { let gkInfo = ''; if (team.goalkeeper && team.goalkeeper.valueInUsd) { let formattedValue; const valueInUsd = team.goalkeeper.valueInUsd; if (valueInUsd >= 1000000) { formattedValue = `${(valueInUsd / 1000000).toFixed(2)}M`; } else { formattedValue = `${(valueInUsd / 1000).toFixed(0)}k`; } gkInfo = ` | GK: $${formattedValue}`; } return `${team.name}: ${team.defensiveConversionRate}% (${team.goalsConceded}/${team.shotsOnTargetReceived} SoT Against)${gkInfo}${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`; }, true); const worstDefensive = createStatCard('Worst GKs (Global)', globalLeaders.worstDefensiveConversion, team => { let gkInfo = ''; if (team.goalkeeper && team.goalkeeper.valueInUsd) { let formattedValue; const valueInUsd = team.goalkeeper.valueInUsd; if (valueInUsd >= 1000000) { formattedValue = `${(valueInUsd / 1000000).toFixed(2)}M`; } else { formattedValue = `${(valueInUsd / 1000).toFixed(0)}k`; } gkInfo = ` | GK: $${formattedValue}`; } return `${team.name}: ${team.defensiveConversionRate}% (${team.goalsConceded}/${team.shotsOnTargetReceived} SoT Against)${gkInfo}${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`; }, true); const luckiest = createStatCard('Luckiest Teams (Global)', globalLeaders.luckiest, team => `${team.name}: +${team.luckIndex}${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`, true); const unluckiest = createStatCard('Unluckiest Teams (Global)', globalLeaders.unluckiest, team => `${team.name}: ${team.luckIndex}${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}`, true); const unluckyMatches = createStatCard('Teams with Most Unlucky Matches (Global)', globalLeaders.mostUnluckyMatches, team => `${team.name}: ${team.unluckyIndex}% (${team.unluckyMatches}/${team.dominatingMatches} matches)${team.players18Count ? ` | Players 18: ${team.players18Count}` : ''}No unlucky matches found.
'; } const luckyMatchesDiv = document.createElement('div'); luckyMatchesDiv.className = 'match-list'; luckyMatchesDiv.dataset.teamId = team.id; luckyMatchesDiv.dataset.matchType = 'lucky'; luckyMatchesDiv.style.display = 'none'; if (team.luckyMatchDetails && team.luckyMatchDetails.length > 0) { team.luckyMatchDetails.forEach(match => { const matchItem = document.createElement('div'); matchItem.className = 'match-item'; const resultClass = match.result === 'W' ? 'win' : (match.result === 'D' ? 'draw' : 'loss'); const matchInfo = match.homeTeam ? `${team.name} vs ${match.opponent}` : `${match.opponent} vs ${team.name}`; matchItem.innerHTML = ` ${matchInfo} SoT: ${match.shotsOnTarget} ${match.score} (${match.result})`; luckyMatchesDiv.appendChild(matchItem); }); } else { luckyMatchesDiv.innerHTML = 'No lucky matches found.
'; } teamDiv.appendChild(unluckyMatchesDiv); teamDiv.appendChild(luckyMatchesDiv); globalTeamsListContainer.appendChild(teamDiv); }); globalTeamsContent.appendChild(globalTeamsListContainer); globalSummaryTab.addEventListener('click', () => { globalSummaryTab.classList.add('active'); globalTeamsTab.classList.remove('active'); globalSummaryContent.classList.add('active'); globalTeamsContent.classList.remove('active'); }); globalTeamsTab.addEventListener('click', () => { globalSummaryTab.classList.remove('active'); globalTeamsTab.classList.add('active'); globalSummaryContent.classList.remove('active'); globalTeamsContent.classList.add('active'); }); globalContent.appendChild(globalSubTabContainer); globalContent.appendChild(globalSummaryContent); globalContent.appendChild(globalTeamsContent); } const selectorContainer = document.createElement('div'); selectorContainer.className = 'league-selector'; const selectorTitle = document.createElement('div'); selectorTitle.className = 'league-selector-title'; selectorTitle.textContent = 'Select a League:'; selectorContainer.appendChild(selectorTitle); const leagueGrid = document.createElement('div'); leagueGrid.className = 'league-grid'; leagueIds.forEach((leagueId, index) => { const leagueButton = document.createElement('div'); leagueButton.className = 'league-item'; if (index === currentActiveLeagueIndex) { leagueButton.classList.add('active'); } const leagueType = allLeaguesData[leagueId].leagueType; const divisionName = getDivisionDisplayName(leagueId, leagueType); const leagueUrl = `https://www.managerzone.com/?p=league&type=${leagueType}&sid=${leagueId}`; leagueButton.innerHTML = `${divisionName}`; leagueButton.dataset.leagueId = leagueId; leagueButton.addEventListener('click', (e) => { if (e.target.closest('.league-link')) { return; } e.preventDefault(); const clickedLeagueId = e.currentTarget.dataset.leagueId; displayLeagueContent(clickedLeagueId); }); leagueGrid.appendChild(leagueButton); }); selectorContainer.appendChild(leagueGrid); const paginationContainer = document.createElement('div'); paginationContainer.className = 'pagination'; paginationContainer.style.marginTop = '15px'; if (leagueIds.length > 1) { const prevButton = document.createElement('button'); prevButton.className = 'pagination-button prev'; prevButton.innerHTML = '« Previous League'; prevButton.disabled = currentActiveLeagueIndex <= 0; prevButton.style.opacity = prevButton.disabled ? '0.5' : '1'; prevButton.addEventListener('click', () => { if (currentActiveLeagueIndex > 0) { displayLeagueContent(leagueIds[currentActiveLeagueIndex - 1]); } }); const nextButton = document.createElement('button'); nextButton.className = 'pagination-button next'; nextButton.innerHTML = 'Next League »'; nextButton.disabled = currentActiveLeagueIndex >= leagueIds.length - 1; nextButton.style.opacity = nextButton.disabled ? '0.5' : '1'; nextButton.addEventListener('click', () => { if (currentActiveLeagueIndex < leagueIds.length - 1) { displayLeagueContent(leagueIds[currentActiveLeagueIndex + 1]); } }); paginationContainer.appendChild(prevButton); paginationContainer.appendChild(nextButton); selectorContainer.appendChild(paginationContainer); } leagueContent.appendChild(selectorContainer); function displayLeagueContent(leagueId) { const newLeagueIndex = leagueIds.indexOf(leagueId); if (newLeagueIndex === -1) return; const leagueData = allLeaguesData[leagueId]; currentActiveLeagueIndex = newLeagueIndex; document.querySelectorAll('.league-item').forEach(item => { item.classList.remove('active'); if (item.dataset.leagueId === leagueId) { item.classList.add('active'); } }); const prevButton = paginationContainer?.querySelector('.pagination-button.prev'); const nextButton = paginationContainer?.querySelector('.pagination-button.next'); if (prevButton) { prevButton.disabled = newLeagueIndex <= 0; prevButton.style.opacity = prevButton.disabled ? '0.5' : '1'; } if (nextButton) { nextButton.disabled = newLeagueIndex >= leagueIds.length - 1; nextButton.style.opacity = nextButton.disabled ? '0.5' : '1'; } const leagueDataContainer = document.createElement('div'); leagueDataContainer.id = 'league-data-container'; displayLeagueData(leagueData.teams, leagueData.statLeaders, leagueId, leagueData.leagueType, leagueDataContainer); const existingContainer = leagueContent.querySelector('#league-data-container'); if (existingContainer) { leagueContent.replaceChild(leagueDataContainer, existingContainer); } else { leagueContent.appendChild(leagueDataContainer); } leagueDataContainer.querySelectorAll('.toggle-matches').forEach(toggle => { toggle.addEventListener('click', function(e) { const teamId = this.dataset.teamId; const matchType = this.dataset.matchType; const parentStatItem = this.closest('.stat-item') || this.closest('.team-stats'); if (!parentStatItem) return; const matchList = parentStatItem.querySelector(`.match-list[data-team-id="${teamId}"][data-match-type="${matchType}"]`); if (matchList) { if (matchList.style.display === 'block') { matchList.style.display = 'none'; this.textContent = "View matches"; } else { matchList.style.display = 'block'; this.textContent = "Hide matches"; } } }); }); globalTab.classList.remove('active'); leagueTab.classList.add('active'); globalContent.classList.remove('active'); leagueContent.classList.add('active'); resultsDiv.scrollTop = 0; } const initialLeagueDataContainer = document.createElement('div'); initialLeagueDataContainer.id = 'league-data-container'; leagueContent.appendChild(initialLeagueDataContainer); if (currentActiveLeagueIndex !== -1) { displayLeagueContent(leagueIds[currentActiveLeagueIndex]); } globalTab.addEventListener('click', () => { globalTab.classList.add('active'); leagueTab.classList.remove('active'); globalContent.classList.add('active'); leagueContent.classList.remove('active'); }); leagueTab.addEventListener('click', () => { globalTab.classList.remove('active'); leagueTab.classList.add('active'); globalContent.classList.remove('active'); leagueContent.classList.add('active'); }); const mainContent = document.createElement('div'); mainContent.appendChild(backButtonContainer); mainContent.appendChild(tabContainer); mainContent.appendChild(globalContent); mainContent.appendChild(leagueContent); resultsDiv.appendChild(mainContent); globalContent.querySelectorAll('.toggle-matches').forEach(toggle => { toggle.addEventListener('click', function(e) { const teamId = this.dataset.teamId; const matchType = this.dataset.matchType; const parentStatItem = this.closest('.stat-item') || this.closest('.team-stats'); if (!parentStatItem) return; const matchList = parentStatItem.querySelector(`.match-list[data-team-id="${teamId}"][data-match-type="${matchType}"]`); if (matchList) { if (matchList.style.display === 'block') { matchList.style.display = 'none'; this.textContent = "View matches"; } else { matchList.style.display = 'block'; this.textContent = "Hide matches"; } } }); }); } async function processMultipleLeagues(leagueEntries, resultsDiv) { const allLeaguesData = {}; const loadingEl = document.createElement('div'); loadingEl.style.display = 'flex'; loadingEl.style.justifyContent = 'center'; loadingEl.style.alignItems = 'center'; loadingEl.style.margin = '30px 0'; loadingEl.innerHTML = ` Processing leagues (0/${leagueEntries.length})...`; resultsDiv.innerHTML = ''; resultsDiv.appendChild(loadingEl); for (let i = 0; i < leagueEntries.length; i++) { const entry = leagueEntries[i]; const leagueId = entry.id; const leagueType = entry.type; const divisionName = getDivisionDisplayName(leagueId, leagueType); loadingEl.innerHTML = ` Processing ${divisionName} (${i+1}/${leagueEntries.length}) - Type: ${leagueType} Step 1/3: Fetching info`; try { const tableUrl = `https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${leagueId}&tid=1&sport=soccer&sub=table`; const scheduleUrl = `https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${leagueId}&tid=1&sport=soccer&sub=schedule`; log(`Processing league ID: ${leagueId} (Type: ${leagueType})`, "info"); const [tableHTML, scheduleHTML] = await Promise.all([makeRequest(tableUrl), makeRequest(scheduleUrl)]); loadingEl.innerHTML = ` Processing ${divisionName} (${i+1}/${leagueEntries.length}) - Type: ${leagueType} Step 2/3: Processing teams`; const teams = extractTeamData(tableHTML); if (teams.length > 0) { const allMatches = extractScheduleData(scheduleHTML, teams); const playedMatches = allMatches.filter(match => /^\d+\s*-\s*\d+$/.test(match.result)); log(`Found ${teams.length} teams and ${playedMatches.length} played matches in league ${leagueId}`, "info"); const teamStats = {}; teams.forEach(team => { teamStats[team.id] = { name: team.name, shotsOnTarget: 0, goalsScored: 0, shotsOnTargetReceived: 0, goalsConceded: 0, matchesPlayed: 0, unluckyMatches: 0, dominatingMatches: 0, luckyWins: 0, outshot: 0, unluckyMatchDetails: [], luckyMatchDetails: [], goalkeeper: null, players18Count: 0 }; }); if (playedMatches.length > 0) { loadingEl.innerHTML = ` Processing ${divisionName} (${i+1}/${leagueEntries.length}) - Type: ${leagueType} Step 3/3: Analyzing matches`; const teamIdMap = {}; teams.forEach(team => { teamIdMap[team.id] = team; }); gkLogging.processedTeams.clear(); gkLogging.teamsWithGk.clear(); gkLogging.matchesUsed.clear(); const batchSize = BATCH_SIZE; const maxMatches = playedMatches.length; for (let j = 0; j < maxMatches; j += batchSize) { const batch = playedMatches.slice(j, j + batchSize); const matchPromises = batch.map(match => processMatchComplete(match.mid, teamIdMap)); const matchResults = await Promise.all(matchPromises); if (j < MAX_GK_LOOKUP_ATTEMPTS * batchSize) { const gkPromises = matchResults.filter(Boolean).map(matchData => extractGoalkeeperData(matchData, teamIdMap)); await Promise.all(gkPromises); } matchResults.forEach(matchData => { if (!matchData) return; if (teamStats[matchData.homeTeam.id]) { const homeStats = teamStats[matchData.homeTeam.id]; homeStats.shotsOnTarget += matchData.homeTeam.shotsOnTarget; homeStats.goalsScored += matchData.homeTeam.goals; homeStats.shotsOnTargetReceived += matchData.awayTeam.shotsOnTarget; homeStats.goalsConceded += matchData.awayTeam.goals; homeStats.matchesPlayed++; if (matchData.homeTeam.shotsOnTarget > matchData.awayTeam.shotsOnTarget) { homeStats.dominatingMatches++; if (matchData.homeTeam.result !== 'W') { homeStats.unluckyMatches++; homeStats.unluckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.awayTeam.name, homeTeam: true, result: matchData.homeTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } if (matchData.homeTeam.shotsOnTarget < matchData.awayTeam.shotsOnTarget) { homeStats.outshot++; if (matchData.homeTeam.result === 'W') { homeStats.luckyWins++; homeStats.luckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.awayTeam.name, homeTeam: true, result: matchData.homeTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } } if (teamStats[matchData.awayTeam.id]) { const awayStats = teamStats[matchData.awayTeam.id]; awayStats.shotsOnTarget += matchData.awayTeam.shotsOnTarget; awayStats.goalsScored += matchData.awayTeam.goals; awayStats.shotsOnTargetReceived += matchData.homeTeam.shotsOnTarget; awayStats.goalsConceded += matchData.homeTeam.goals; awayStats.matchesPlayed++; if (matchData.awayTeam.shotsOnTarget > matchData.homeTeam.shotsOnTarget) { awayStats.dominatingMatches++; if (matchData.awayTeam.result !== 'W') { awayStats.unluckyMatches++; awayStats.unluckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.homeTeam.name, homeTeam: false, result: matchData.awayTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } if (matchData.awayTeam.shotsOnTarget < matchData.homeTeam.shotsOnTarget) { awayStats.outshot++; if (matchData.awayTeam.result === 'W') { awayStats.luckyWins++; awayStats.luckyMatchDetails.push({ mid: matchData.mid, opponent: matchData.homeTeam.name, homeTeam: false, result: matchData.awayTeam.result, score: `${matchData.homeTeam.goals}-${matchData.awayTeam.goals}`, shotsOnTarget: `${matchData.homeTeam.shotsOnTarget}-${matchData.awayTeam.shotsOnTarget}` }); } } } }); loadingEl.innerHTML = ` Processing ${divisionName} (${i+1}/${leagueEntries.length}) - Type: ${leagueType} Step 3/3: Analyzing matches (${Math.min(j + batch.length, maxMatches)}/${maxMatches} processed) (Found: ${gkLogging.teamsWithGk.size}/${teams.length} GKs)`; } } teams.forEach(team => { if (teamGoalkeeperCache[team.id] && teamStats[team.id]) { teamStats[team.id].goalkeeper = teamGoalkeeperCache[team.id]; } if (teamPlayersCache[team.id] && teamStats[team.id]) { teamStats[team.id].players18Count = teamPlayersCache[team.id].players18Count || 0; } }); const validTeams = []; teams.forEach(team => { const stats = teamStats[team.id] || { shotsOnTarget: 0, goalsScored: 0, shotsOnTargetReceived: 0, goalsConceded: 0, matchesPlayed: 0, unluckyMatches: 0, dominatingMatches: 0, luckyWins: 0, outshot: 0, unluckyMatchDetails: [], luckyMatchDetails: [], goalkeeper: null, players18Count: 0 }; if (stats.shotsOnTarget === 0 || stats.shotsOnTargetReceived === 0) { log(`Excluding team ${team.name} (${team.id}) - Has 0 shots on target (for: ${stats.shotsOnTarget}, against: ${stats.shotsOnTargetReceived})`, "warn"); return; } team.shotsOnTarget = stats.shotsOnTarget; team.goalsScored = stats.goalsScored; team.shotsOnTargetReceived = stats.shotsOnTargetReceived; team.goalsConceded = stats.goalsConceded; team.matchesPlayed = stats.matchesPlayed; team.unluckyMatches = stats.unluckyMatches; team.dominatingMatches = stats.dominatingMatches; team.luckyWins = stats.luckyWins; team.outshot = stats.outshot; team.unluckyMatchDetails = stats.unluckyMatchDetails; team.luckyMatchDetails = stats.luckyMatchDetails; team.goalkeeper = stats.goalkeeper; team.players18Count = stats.players18Count; team.offensiveConversionRate = stats.shotsOnTarget > 0 ? (stats.goalsScored / stats.shotsOnTarget * 100).toFixed(1) : '0.0'; team.defensiveConversionRate = stats.shotsOnTargetReceived > 0 ? (stats.goalsConceded / stats.shotsOnTargetReceived * 100).toFixed(1) : '0.0'; let luckIndex = parseFloat(team.offensiveConversionRate) - parseFloat(team.defensiveConversionRate); if (team.goalkeeper && team.goalkeeper.valueInUsd) { const gkValueFactor = Math.min(team.goalkeeper.valueInUsd / 1000000, 5) * 0.5; luckIndex -= gkValueFactor; log(`Team ${team.name} GK adjustment: ${team.goalkeeper.valueInUsd.toFixed(2)} USD = -${gkValueFactor.toFixed(1)} luck points`, "gk"); } team.luckIndex = luckIndex.toFixed(1); team.unluckyIndex = stats.dominatingMatches > 0 ? ((stats.unluckyMatches / stats.dominatingMatches) * 100).toFixed(1) : '0.0'; team.luckyWinPct = stats.outshot > 0 ? ((stats.luckyWins / stats.outshot) * 100).toFixed(1) : '0.0'; if (stats.dominatingMatches > 0) { const unluckyPct = stats.unluckyMatches / stats.dominatingMatches; const sampleWeight = 1 + Math.log(Math.max(stats.dominatingMatches, 1)) / 10; team.weightedUnluckyScore = (unluckyPct * sampleWeight * 100).toFixed(1); } else { team.weightedUnluckyScore = '0.0'; } if (stats.outshot > 0) { const luckyPct = stats.luckyWins / stats.outshot; const sampleWeight = 1 + Math.log(Math.max(stats.outshot, 1)) / 10; team.weightedLuckyScore = (luckyPct * sampleWeight * 100).toFixed(1); } else { team.weightedLuckyScore = '0.0'; } validTeams.push(team); }); log(`Filtered teams: ${validTeams.length} of ${teams.length} teams have valid shot data`, "info"); const statLeaders = { bestOffensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.offensiveConversionRate) - parseFloat(a.offensiveConversionRate)).slice(0, 3), worstOffensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.offensiveConversionRate) - parseFloat(b.offensiveConversionRate)).slice(0, 3), bestDefensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.defensiveConversionRate) - parseFloat(b.defensiveConversionRate)).slice(0, 3), worstDefensiveConversion: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.defensiveConversionRate) - parseFloat(a.defensiveConversionRate)).slice(0, 3), luckiest: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(b.luckIndex) - parseFloat(a.luckIndex)).slice(0, 3), unluckiest: validTeams.filter(team => team.matchesPlayed > 0).sort((a, b) => parseFloat(a.luckIndex) - parseFloat(b.luckIndex)).slice(0, 3), mostUnluckyMatches: validTeams.filter(team => team.dominatingMatches > 0).sort((a, b) => parseFloat(b.weightedUnluckyScore) - parseFloat(a.weightedUnluckyScore)).slice(0, 3), mostLuckyWins: validTeams.filter(team => team.outshot > 0).sort((a, b) => parseFloat(b.weightedLuckyScore) - parseFloat(a.weightedLuckyScore)).slice(0, 3) }; if (playedMatches.length > 0 && validTeams.length > 0) { allLeaguesData[leagueId] = { teams: validTeams, statLeaders, leagueType }; } } } catch (error) { log(`Error processing league ${leagueId} (Type: ${leagueType}): ${error.message}`, "error"); continue; } loadingEl.innerHTML = ` Processed ${divisionName} (${i+1}/${leagueEntries.length})`; } loadingEl.innerHTML = ` Finalizing global statistics...`; displayGkDebugInfo(); updateGlobalLeaders(allLeaguesData); const leagueIds = Object.keys(allLeaguesData) .filter(key => key !== 'globalLeaders') .sort((a, b) => parseInt(a) - parseInt(b)); if (leagueIds.length > 0) { updateLeagueSelector(allLeaguesData, resultsDiv, leagueIds[0]); } else { resultsDiv.innerHTML = 'No leagues with valid match data found in the specified leagues.
'; showBackButton(resultsDiv); } } function showLeagueInputForm(resultsDiv) { const formDiv = document.createElement('div'); formDiv.style.marginBottom = '20px'; const header = document.createElement('p'); header.textContent = 'Add leagues (by ID & Type) to analyze:'; formDiv.appendChild(header); const leagueEntryContainer = document.createElement('div'); leagueEntryContainer.className = 'league-entry-container'; const entryForm = document.createElement('div'); entryForm.className = 'league-entry-form'; const sidInput = document.createElement('input'); sidInput.type = 'text'; sidInput.placeholder = 'League IDs (e.g., 1, 2, 3)'; sidInput.autocomplete = 'off'; const typeSelect = document.createElement('select'); LEAGUE_TYPES.forEach(lt => { const option = document.createElement('option'); option.value = lt.value; option.textContent = lt.label; typeSelect.appendChild(option); }); const addButton = document.createElement('button'); addButton.className = 'add-button'; addButton.innerHTML = '+'; addButton.title = 'Add Leagues'; entryForm.appendChild(sidInput); entryForm.appendChild(typeSelect); entryForm.appendChild(addButton); const leagueList = document.createElement('div'); leagueList.className = 'league-list'; leagueList.style.display = 'none'; const leagues = []; const updateSubmitButton = () => { submitButton.disabled = leagues.length === 0; submitButton.style.opacity = submitButton.disabled ? 0.6 : 1; submitButton.style.cursor = submitButton.disabled ? 'not-allowed' : 'pointer'; }; function updateLeagueList() { if (leagues.length === 0) { leagueList.style.display = 'none'; updateSubmitButton(); return; } leagueList.style.display = 'block'; leagueList.innerHTML = ''; leagues.forEach((league, index) => { const leagueItem = document.createElement('div'); leagueItem.className = 'league-list-item'; const divisionName = getDivisionDisplayName(league.id, league.type); const typeLabel = LEAGUE_TYPES.find(lt => lt.value === league.type)?.label || league.type; leagueItem.innerHTML = `Processing ${leagues.length} leagues...
`; processMultipleLeagues(leagues, resultsDiv); } }); leagueEntryContainer.appendChild(entryForm); leagueEntryContainer.appendChild(leagueList); formDiv.appendChild(leagueEntryContainer); formDiv.appendChild(submitButton); resultsDiv.innerHTML = ''; resultsDiv.appendChild(formDiv); showBackButton(resultsDiv); setTimeout(() => sidInput.focus(), 100); } function showSidPrompt(resultsDiv, isSpecificOption = false) { if (isSpecificOption) { const currentLeagueId = getCurrentLeagueId(); const currentLeagueType = getCurrentLeagueType(); const formDiv = document.createElement('div'); formDiv.style.marginBottom = '20px'; formDiv.innerHTML = `Please enter a league ID and select type:
Loading data for ${divisionName} (Type: ${type})...
`; processLeagueData(sid, resultsDiv, null, type); } else { let errorMsg = 'Please enter a valid league ID (numbers only).'; formDiv.insertAdjacentHTML('afterbegin', `${errorMsg}
`); } }; sidSubmit.addEventListener('click', handleSubmit); sidInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') handleSubmit(); }); showBackButton(resultsDiv); setTimeout(() => sidInput.focus(), 100); } else { const leagueId = getCurrentLeagueId(); const leagueType = getCurrentLeagueType(); if (!leagueId || !leagueType) { resultsDiv.innerHTML = `Error: Could not detect league ID or type from URL.
`; showBackButton(resultsDiv); return; } const divisionName = getDivisionDisplayName(leagueId, leagueType); resultsDiv.innerHTML = `Loading data for ${divisionName} (Type: ${leagueType})...
`; processLeagueData(leagueId, resultsDiv, null, leagueType); } } function findUnluckyTeams(scope) { document.querySelectorAll('.unluckyOption').forEach(option => { option.style.display = 'none'; }); const resultsDiv = document.getElementById('unluckyResults'); resultsDiv.style.display = 'block'; resultsDiv.innerHTML = ''; if (scope === 'all') { showLeagueInputForm(resultsDiv); } else if (scope === 'current') { const leagueId = getCurrentLeagueId(); const leagueType = getCurrentLeagueType(); if (!leagueId || !leagueType) { resultsDiv.innerHTML = 'Could not detect league ID or type from URL.
'; showBackButton(resultsDiv); return; } showSidPrompt(resultsDiv, false); } else if (scope === 'specific') { showSidPrompt(resultsDiv, true); } } function initializeScript() { createModal(); addUnluckyButton(); log("MZ-Unlucky initialized - 私たちは最高の防御を持っています!", "success"); } if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(initializeScript, 500); } else { window.addEventListener('load', () => { setTimeout(initializeScript, 500); }); } })();