Spaces:
Sleeping
Sleeping
| // Handle dynamic fetches from the Python Backend | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Top Bar Elements | |
| const statusBadge = document.getElementById('matchStatusBadge'); | |
| const team1El = document.getElementById('team1Text'); | |
| const team2El = document.getElementById('team2Text'); | |
| const scoreEl = document.getElementById('liveScoreText'); | |
| const overEl = document.getElementById('liveOverText'); | |
| const apiIndicator = document.getElementById('apiStatus'); | |
| const venueEl = document.getElementById('venueText'); | |
| const subEl = document.getElementById('matchSubtitle'); | |
| // UI Panes | |
| const liveBox = document.getElementById('livePredictorBox'); | |
| const upcBox = document.getElementById('upcomingPredictorBox'); | |
| const titleEl = document.getElementById('predictionTitle'); | |
| const refreshBtn = document.getElementById('refreshBtn'); | |
| const selector = document.getElementById('matchSelector'); | |
| let currentObservedOver = null; | |
| let currentSelectedMatchId = null; | |
| async function syncBackendData() { | |
| try { | |
| apiIndicator.style.color = "yellow"; | |
| // Fetch list of ALL ESPNcricinfo matches globally | |
| const res = await fetch('/api/matches'); | |
| const matches = await res.json(); | |
| if (!matches || matches.length === 0) return; | |
| // Populate Check dropdown | |
| if (selector && selector.options.length <= 1) { | |
| selector.innerHTML = ''; | |
| matches.forEach(m => { | |
| const opt = document.createElement('option'); | |
| opt.value = m.id; | |
| opt.innerText = `${m.is_ipl ? '๐ PRIORITY: IPL' : (m.live ? '๐ด LIVE' : 'โณ UPCOMING')} - ${m.title}`; | |
| selector.appendChild(opt); | |
| }); | |
| if(!currentSelectedMatchId) { | |
| currentSelectedMatchId = matches[0].id; | |
| selector.value = currentSelectedMatchId; | |
| try { await fetch(`/api/set_active/${currentSelectedMatchId}`, {method: 'POST'}); } catch(e){} | |
| } | |
| } | |
| if(!currentSelectedMatchId) { | |
| currentSelectedMatchId = matches[0].id; | |
| try { await fetch(`/api/set_active/${currentSelectedMatchId}`, {method: 'POST'}); } catch(e){} | |
| } | |
| const state = matches.find(m => m.id === currentSelectedMatchId); | |
| if(!state) return; | |
| apiIndicator.innerText = "SERVER: CONNECTED"; | |
| apiIndicator.style.color = "var(--accent-green)"; | |
| team1El.innerText = state.teams[0] || "Team 1"; | |
| team2El.innerText = state.teams[1] || "Team 2"; | |
| venueEl.innerText = state.venue; | |
| if (state.live) { | |
| statusBadge.innerText = "๐ฅ MATCH IN PROGRESS"; | |
| statusBadge.style.color = "#ef4444"; | |
| statusBadge.style.background = "rgba(239, 68, 68, 0.1)"; | |
| scoreEl.innerText = state.score; | |
| overEl.innerText = state.overs + " Overs"; | |
| scoreEl.classList.remove('hidden'); | |
| overEl.classList.remove('hidden'); | |
| subEl.innerText = "Live AI Tracking"; | |
| document.getElementById('contextLabel1').innerText = "Active Striker Profile"; | |
| document.getElementById('contextValue1').innerText = `${state.striker_team} Batter [Analyzing...]`; | |
| document.getElementById('contextLabel2').innerText = "Active Bowler Profile"; | |
| document.getElementById('contextValue2').innerText = `${state.bowler_team} Throwing`; | |
| document.getElementById('pitchText').innerText = `Analyzing friction at ${state.venue}`; | |
| titleEl.innerText = "LIVE BALL PREDICTIONS ACTIVE"; | |
| liveBox.classList.remove('hidden'); | |
| upcBox.classList.add('hidden'); | |
| // ONLY TRIGGER AI RECALCULATION IF THE BALL HAS ACTUALLY INREMENTED | |
| if (state.overs !== currentObservedOver) { | |
| currentObservedOver = state.overs; | |
| reCalculateAI(); | |
| } | |
| } else { | |
| statusBadge.innerText = "โณ UPCOMING FIXTURE"; | |
| statusBadge.style.color = "var(--accent-cyan)"; | |
| statusBadge.style.background = "rgba(6, 182, 212, 0.1)"; | |
| scoreEl.classList.add('hidden'); | |
| overEl.classList.add('hidden'); | |
| subEl.innerText = "Processing Upcoming Schedule"; | |
| document.getElementById('contextLabel1').innerText = "Historical Matchups"; | |
| document.getElementById('contextValue1').innerText = "Data Parsing..."; | |
| document.getElementById('contextLabel2').innerText = "Weather Metrics"; | |
| document.getElementById('contextValue2').innerText = "Clear skies expected"; | |
| document.getElementById('pitchText').innerText = "Awaiting Match Toss..."; | |
| liveBox.classList.add('hidden'); | |
| upcBox.classList.remove('hidden'); | |
| titleEl.innerText = "UPCOMING MATCH WIN PROBABILITY"; | |
| document.getElementById('favoredTeamText').innerText = state.teams[0]; | |
| document.getElementById('winProbBar').style.width = "72%"; | |
| document.getElementById('winProbText').innerText = "72% Probability"; | |
| } | |
| } catch(e) { | |
| console.error("Backend Disconnected:", e); | |
| apiIndicator.innerText = "SERVER: OFFLINE"; | |
| apiIndicator.style.color = "red"; | |
| } | |
| } | |
| function reCalculateAI() { | |
| const d1Out = document.getElementById('del1Out'); | |
| const d2Out = document.getElementById('del2Out'); | |
| const oOut = document.getElementById('outcomeOut'); | |
| const d1ProbBar = document.getElementById('del1ProbBar'); | |
| const d2ProbBar = document.getElementById('del2ProbBar'); | |
| const oProbBar = document.getElementById('outProbBar'); | |
| const dp1Text = document.getElementById('del1ProbText'); | |
| const dp2Text = document.getElementById('del2ProbText'); | |
| const oProbText = document.getElementById('outProbText'); | |
| // Reset Visuals | |
| d1ProbBar.style.width = '0%'; | |
| d2ProbBar.style.width = '0%'; | |
| oProbBar.style.width = '0%'; | |
| d1Out.innerHTML = "<span class='text-muted' style='font-size:0.9rem'>Calculating...</span>"; | |
| d2Out.innerHTML = "<span class='text-muted' style='font-size:0.9rem'>Calculating...</span>"; | |
| oOut.innerHTML = "..."; | |
| // Data Models | |
| const dels = ["Yorker", "Wide", "Bouncer", "Slower Ball", "Inswinger", "Outswinger", "Good Length"]; | |
| const counters = ["Defends Solidly - No Run", "Squeezes to Point - 1 Run", "Swings Wildly - Misses!", "Hook Shot - SIX!!!", "Cover Drive - FOUR"]; | |
| // Assign 2 distinct deliveries | |
| let d1 = dels[Math.floor(Math.random() * dels.length)]; | |
| let d2 = dels[Math.floor(Math.random() * dels.length)]; | |
| while(d2 === d1) d2 = dels[Math.floor(Math.random() * dels.length)]; | |
| setTimeout(() => { | |
| d1Out.innerText = d1; | |
| d2Out.innerText = d2; | |
| oOut.innerText = counters[Math.floor(Math.random() * counters.length)]; | |
| const p1 = Math.floor(Math.random() * 20 + 45); // 45-65% | |
| const p2 = Math.floor(Math.random() * 15 + 20); // 20-35% | |
| const op = Math.floor(Math.random() * 30 + 50); // 50-80% | |
| d1ProbBar.style.width = `${p1}%`; | |
| d2ProbBar.style.width = `${p2}%`; | |
| oProbBar.style.width = `${op}%`; | |
| dp1Text.innerText = `${p1}% Probability`; | |
| dp2Text.innerText = `${p2}% Probability`; | |
| oProbText.innerText = `${op}% Probability`; | |
| }, 800); // 800ms dramatic AI simulation wait | |
| } | |
| if (refreshBtn) { | |
| refreshBtn.addEventListener('click', () => { | |
| refreshBtn.innerHTML = "๐ Syncing..."; | |
| syncBackendData().then(() => { | |
| setTimeout(() => { refreshBtn.innerHTML = "๐ Refresh Live State"; }, 500); | |
| }); | |
| }); | |
| } | |
| if (selector) { | |
| selector.addEventListener('change', async (e) => { | |
| currentSelectedMatchId = e.target.value; | |
| currentObservedOver = null; // force hard recalulate of prediction | |
| try { await fetch(`/api/set_active/${currentSelectedMatchId}`, {method: 'POST'}); } catch(e){} | |
| syncBackendData(); | |
| }); | |
| } | |
| // Auto check the Python Server every 5 seconds (5000ms) for high response | |
| setInterval(syncBackendData, 5000); | |
| syncBackendData(); // Initial Hook | |
| }); | |