AstraOS Ver. 1.36:
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s

- AyranTracker bearbeitet
This commit is contained in:
elias 2026-06-07 13:07:02 +02:00
parent fd420d7733
commit d3ecd7deb9
2 changed files with 34 additions and 20 deletions

View file

@ -47,25 +47,29 @@
<span id="rankFallbackIcon" class="text-xl">🏆</span> <span id="rankFallbackIcon" class="text-xl">🏆</span>
</div> </div>
<div> <div>
<p class="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Current Rank</p> <p class="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Rank</p>
<p id="displayRank" class="text-lg font-black text-purple-300">Loading...</p> <p id="displayRank" class="text-lg font-black text-purple-300">Loading...</p>
<p id="displayRR" class="text-xs text-slate-500">-- RR</p> <p id="displayRR" class="text-xs text-slate-500">-- RR</p>
</div> </div>
</div> </div>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6"> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl"> <div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Win Rate</p> <p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Win Rate</p>
<p id="calcWinrate" class="text-2xl font-black text-emerald-400">--</p> <p id="calcWinrate" class="text-2xl font-black text-emerald-400">--</p>
</div> </div>
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl"> <div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Average K/D Ratio</p> <p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Ø Headshot %</p>
<p id="calcHSPercentage" class="text-2xl font-black text-purple-400">--</p>
</div>
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Average K/D</p>
<p id="calcKD" class="text-2xl font-black text-slate-100">--</p> <p id="calcKD" class="text-2xl font-black text-slate-100">--</p>
</div> </div>
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl"> <div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Best Agent (by KDA)</p> <p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Best Agent</p>
<p id="calcBestAgent" class="text-2xl font-black text-purple-400">--</p> <p id="calcBestAgent" class="text-2xl font-black text-indigo-400">--</p>
</div> </div>
</div> </div>
@ -114,7 +118,7 @@
<p id="modalKDA" class="text-base font-black text-slate-200 mt-0.5">0 / 0 / 0</p> <p id="modalKDA" class="text-base font-black text-slate-200 mt-0.5">0 / 0 / 0</p>
</div> </div>
<div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center"> <div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center">
<p class="text-[10px] text-slate-500 uppercase font-bold">Kampfwert (ACS)</p> <p class="text-[10px] text-slate-500 uppercase font-bold">Average Combat Score</p>
<p id="modalACS" class="text-base font-black text-purple-300 mt-0.5">--</p> <p id="modalACS" class="text-base font-black text-purple-300 mt-0.5">--</p>
</div> </div>
</div> </div>
@ -140,17 +144,17 @@
</div> </div>
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl space-y-3"> <div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl space-y-3">
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-1">Gefechtsmetriken</h4> <h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-1">Match-Stats</h4>
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5"> <div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
<span class="text-slate-400">First Bloods (Erste Kills):</span> <span class="text-slate-400">First Bloods:</span>
<span id="modalFB" class="font-bold text-amber-400">0</span> <span id="modalFB" class="font-bold text-amber-400">0</span>
</div> </div>
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5"> <div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
<span class="text-slate-400">Ø Budgetausgabe/Runde:</span> <span class="text-slate-400">Ø Credits Spent/Runde:</span>
<span id="modalEcon" class="font-bold text-slate-200">0 ¥</span> <span id="modalEcon" class="font-bold text-slate-200">0 ¥</span>
</div> </div>
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5"> <div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
<span class="text-slate-400">Auszeichnungen:</span> <span class="text-slate-400">Titel:</span>
<span id="modalBadges" class="font-bold text-purple-400">Keine</span> <span id="modalBadges" class="font-bold text-purple-400">Keine</span>
</div> </div>
<div class="flex justify-between text-xs"> <div class="flex justify-between text-xs">
@ -164,7 +168,7 @@
</div> </div>
<script> <script>
let currentMatchesCache = []; // Globaler Cache für Klick-Events auf Matches let currentMatchesCache = []; // Globaler Cache für Match-Klicks
function openMatchReport(index) { function openMatchReport(index) {
const match = currentMatchesCache[index]; const match = currentMatchesCache[index];
@ -189,7 +193,7 @@
// Gefechtsmetriken binden // Gefechtsmetriken binden
document.getElementById('modalFB').innerText = match.details.first_bloods; document.getElementById('modalFB').innerText = match.details.first_bloods;
document.getElementById('modalEcon').innerText = match.details.avg_spent; document.getElementById('modalEcon').innerText = match.details.avg_spent;
document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Auszeichnung"; document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Titel";
document.getElementById('modalMulti').innerText = `3K: ${match.details.multikills['3k']} | 4K: ${match.details.multikills['4k']} | Ace: ${match.details.multikills['5k']}`; document.getElementById('modalMulti').innerText = `3K: ${match.details.multikills['3k']} | 4K: ${match.details.multikills['4k']} | Ace: ${match.details.multikills['5k']}`;
const modal = document.getElementById('matchModal'); const modal = document.getElementById('matchModal');
@ -224,12 +228,11 @@
btn.disabled = true; btn.disabled = true;
try { try {
// Hier lag der Fehler: ?mode=competitive hat die restlichen Argumente wie size überschrieben. Jetzt sauber gelöst.
const response = await fetch(`/api/v1/profile/${encodeURIComponent(name)}/${encodeURIComponent(tag)}?mode=competitive`); const response = await fetch(`/api/v1/profile/${encodeURIComponent(name)}/${encodeURIComponent(tag)}?mode=competitive`);
const data = await response.json(); const data = await response.json();
if (data.status === "success") { if (data.status === "success") {
currentMatchesCache = data.matches; // Daten sicher cachen currentMatchesCache = data.matches;
document.getElementById('displayPlayerName').innerText = data.account.name; document.getElementById('displayPlayerName').innerText = data.account.name;
document.getElementById('displayPlayerTag').innerText = `#${data.account.tag.toUpperCase()}`; document.getElementById('displayPlayerTag').innerText = `#${data.account.tag.toUpperCase()}`;
@ -255,7 +258,9 @@
cardDiv.innerText = ''; cardDiv.innerText = '';
} }
// Globale Profildaten binden
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate; document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
document.getElementById('calcHSPercentage').innerText = data.calculated_stats.avg_hs_percentage; // Bindung der neuen Statistik
document.getElementById('calcKD').innerText = data.calculated_stats.kd_ratio; document.getElementById('calcKD').innerText = data.calculated_stats.kd_ratio;
document.getElementById('calcBestAgent').innerText = data.calculated_stats.best_agent; document.getElementById('calcBestAgent').innerText = data.calculated_stats.best_agent;
@ -280,7 +285,6 @@
rrClass = "text-rose-400 bg-rose-950/40 border border-rose-900/30"; rrClass = "text-rose-400 bg-rose-950/40 border border-rose-900/30";
} }
// Jedes generierte Match-Item ruft per onclick mit seinem Index openMatchReport() auf
const matchHTML = ` const matchHTML = `
<div onclick="openMatchReport(${index})" class="bg-slate-900/60 border-l-4 ${borderColor} rounded-r-xl p-3.5 flex justify-between items-center text-xs sm:text-sm transition hover:bg-purple-950/20 hover:border-purple-500 cursor-pointer select-none"> <div onclick="openMatchReport(${index})" class="bg-slate-900/60 border-l-4 ${borderColor} rounded-r-xl p-3.5 flex justify-between items-center text-xs sm:text-sm transition hover:bg-purple-950/20 hover:border-purple-500 cursor-pointer select-none">
<div> <div>

View file

@ -1558,7 +1558,7 @@ def get_valorant_stats(name, tag):
mmr_data = mmr_res.json().get('data', {}) if mmr_res.status_code == 200 else {} mmr_data = mmr_res.json().get('data', {}) if mmr_res.status_code == 200 else {}
if not mmr_data: mmr_data = {} if not mmr_data: mmr_data = {}
# 3. RR-Verlauf (MMR History) für die Matches abrufen # 3. RR-Verlauf (MMR History)
rr_history = {} rr_history = {}
if match_mode == 'competitive': if match_mode == 'competitive':
history_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr-history/{region}/{name}/{tag}", headers=headers, history_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr-history/{region}/{name}/{tag}", headers=headers,
@ -1569,7 +1569,7 @@ def get_valorant_stats(name, tag):
if m_id: if m_id:
rr_history[m_id] = h_item.get('mmr_change_to_last_game', 0) rr_history[m_id] = h_item.get('mmr_change_to_last_game', 0)
# 4. Match Historie: Hier wird size=20 explizit erzwungen! # 4. Match Historie abrufen (Wichtig: Erzwingt das Limit auf size=20)
matches_res = requests.get(f"{VALORANT_API_BASE}/v3/matches/{region}/{name}/{tag}?size=20&mode={match_mode}", matches_res = requests.get(f"{VALORANT_API_BASE}/v3/matches/{region}/{name}/{tag}?size=20&mode={match_mode}",
headers=headers, timeout=10) headers=headers, timeout=10)
matches_list = matches_res.json().get('data', []) if matches_res.status_code == 200 else [] matches_list = matches_res.json().get('data', []) if matches_res.status_code == 200 else []
@ -1580,6 +1580,10 @@ def get_valorant_stats(name, tag):
total_deaths = 0 total_deaths = 0
total_assists = 0 total_assists = 0
# Variablen für globale Headshot-Berechnung
global_headshots = 0
global_total_hits = 0
agent_stats = {} agent_stats = {}
processed_matches = [] processed_matches = []
@ -1634,18 +1638,22 @@ def get_valorant_stats(name, tag):
else: else:
score_str = f"{blue_rounds} : {red_rounds}" score_str = f"{blue_rounds} : {red_rounds}"
# --- ERWEITERTE DETAILANALYSE --- # Wirtschaft ausrechnen
economy = me.get('economy', {}) economy = me.get('economy', {})
spent_spent = economy.get('spent', {}).get('overall', 0) or 0 spent_spent = economy.get('spent', {}).get('overall', 0) or 0
avg_spent = round(spent_spent / rounds_played, 0) if rounds_played > 0 else 0 avg_spent = round(spent_spent / rounds_played, 0) if rounds_played > 0 else 0
# Hit-Zonen auswerten # Hit-Zonen auswerten (Match)
headshots = stats.get('headshots', 0) or 0 headshots = stats.get('headshots', 0) or 0
bodyshots = stats.get('bodyshots', 0) or 0 bodyshots = stats.get('bodyshots', 0) or 0
legshots = stats.get('legshots', 0) or 0 legshots = stats.get('legshots', 0) or 0
total_hits = headshots + bodyshots + legshots total_hits = headshots + bodyshots + legshots
hs_rate = round((headshots / total_hits) * 100, 1) if total_hits > 0 else 0 hs_rate = round((headshots / total_hits) * 100, 1) if total_hits > 0 else 0
# Für globale Statistik aufsummieren
global_headshots += headshots
global_total_hits += total_hits
# First Bloods & Multi-Kills # First Bloods & Multi-Kills
first_bloods = 0 first_bloods = 0
kills_per_round = {3: 0, 4: 0, 5: 0} kills_per_round = {3: 0, 4: 0, 5: 0}
@ -1707,9 +1715,10 @@ def get_valorant_stats(name, tag):
} }
}) })
# Berechnungen für globale Stats # Berechnungen für globale Profile-Stats
kd_calculated = round(total_kills / total_deaths, 2) if total_deaths > 0 else total_kills kd_calculated = round(total_kills / total_deaths, 2) if total_deaths > 0 else total_kills
winrate_calculated = round((wins / match_count) * 100, 1) if match_count > 0 else 0 winrate_calculated = round((wins / match_count) * 100, 1) if match_count > 0 else 0
global_hs_calculated = round((global_headshots / global_total_hits) * 100, 1) if global_total_hits > 0 else 0
all_agents = [] all_agents = []
best_agent_name = "Keiner" best_agent_name = "Keiner"
@ -1748,6 +1757,7 @@ def get_valorant_stats(name, tag):
}, },
"calculated_stats": { "calculated_stats": {
"win_rate": f"{winrate_calculated}%", "win_rate": f"{winrate_calculated}%",
"avg_hs_percentage": f"{global_hs_calculated}%", # Neue API-Rückgabe
"kd_ratio": str(kd_calculated), "kd_ratio": str(kd_calculated),
"best_agent": best_agent_name, "best_agent": best_agent_name,
"matches_analyzed": match_count "matches_analyzed": match_count