AstraOS Ver. 1.34:
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
- AyranTracker bearbeitet
This commit is contained in:
parent
f6bbc601b5
commit
c5faf7f85d
|
|
@ -70,9 +70,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
|
|
||||||
<div class="lg:col-span-2 bg-slate-950/40 border border-purple-900/20 rounded-2xl p-5">
|
<div class="lg:col-span-2 bg-slate-950/40 border border-purple-900/20 rounded-2xl p-5">
|
||||||
<h3 id="matchHistoryHeader" class="text-sm font-bold uppercase tracking-wider mb-4 text-slate-300">Recent Matches</h3>
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h3 id="matchHistoryHeader" class="text-sm font-bold uppercase tracking-wider text-slate-300">Recent Matches</h3>
|
||||||
|
<span class="text-[10px] text-purple-400 font-semibold bg-purple-950/50 border border-purple-900/40 px-2 py-0.5 rounded">Für Details anklicken</span>
|
||||||
|
</div>
|
||||||
<div id="matchHistoryContainer" class="space-y-2.5"></div>
|
<div id="matchHistoryContainer" class="space-y-2.5"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -88,7 +90,119 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="matchModal" class="fixed inset-0 bg-black/80 backdrop-blur-md hidden items-center justify-center z-50 p-4">
|
||||||
|
<div class="bg-slate-950 border border-purple-900/60 w-full max-w-2xl rounded-2xl shadow-2xl p-6 overflow-y-auto max-h-[90vh]">
|
||||||
|
<div class="flex justify-between items-start border-b border-purple-950 pb-4 mb-4">
|
||||||
|
<div>
|
||||||
|
<h3 id="modalMapName" class="text-xl font-black tracking-wide text-slate-100">Ascent</h3>
|
||||||
|
<p id="modalGameMeta" class="text-xs text-slate-400 mt-0.5">Competitive • Frankfurt Server</p>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeMatchModal()" class="text-slate-400 hover:text-white font-bold bg-slate-900 border border-slate-800 rounded-lg p-2 text-xs transition">✕ Schließen</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-6">
|
||||||
|
<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">Ergebnis</p>
|
||||||
|
<p id="modalResult" class="text-base font-black mt-0.5">WIN</p>
|
||||||
|
</div>
|
||||||
|
<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">Agent</p>
|
||||||
|
<p id="modalAgent" class="text-base font-black text-purple-400 mt-0.5">Jett</p>
|
||||||
|
</div>
|
||||||
|
<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">K / D / A</p>
|
||||||
|
<p id="modalKDA" class="text-base font-black text-slate-200 mt-0.5">0 / 0 / 0</p>
|
||||||
|
</div>
|
||||||
|
<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 id="modalACS" class="text-base font-black text-purple-300 mt-0.5">240</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
|
||||||
|
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl">
|
||||||
|
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Zielgenauigkeit (Hit-Zonen)</h4>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between text-xs mb-1">
|
||||||
|
<span class="text-purple-300">Kopf (Headshot Rate)</span>
|
||||||
|
<span id="modalHSRate" class="font-bold">0%</span>
|
||||||
|
</div>
|
||||||
|
<div class="w-full bg-slate-900 h-2 rounded-full overflow-hidden">
|
||||||
|
<div id="modalHSBar" class="bg-purple-500 h-full" style="width: 0%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-[11px] text-slate-500 mt-2">
|
||||||
|
Treffer: <span id="modalHitsCount" class="text-slate-300">0 Head / 0 Body / 0 Legs</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<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 id="modalFB" class="font-bold text-amber-400">0</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
|
||||||
|
<span class="text-slate-400">Wirtschaft (Ø Ausgaben/Runde):</span>
|
||||||
|
<span id="modalEcon" class="font-bold text-slate-200">0 ¥</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
|
||||||
|
<span class="text-slate-400">Auszeichnungen:</span>
|
||||||
|
<span id="modalBadges" class="font-bold text-purple-400">Keine</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between text-xs">
|
||||||
|
<span class="text-slate-400">Multi-Kills:</span>
|
||||||
|
<span id="modalMulti" class="font-bold text-slate-300">3K: 0 | 4K: 0 | 5K: 0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
let currentMatchesCache = []; // Hält die Match-Metadaten lokal für das Anklicken vor
|
||||||
|
|
||||||
|
function openMatchReport(index) {
|
||||||
|
const match = currentMatchesCache[index];
|
||||||
|
if (!match) return;
|
||||||
|
|
||||||
|
document.getElementById('modalMapName').innerText = match.map;
|
||||||
|
document.getElementById('modalGameMeta').innerText = `${match.mode} • ${match.details.game_length} • ${match.details.server}`;
|
||||||
|
|
||||||
|
const resEl = document.getElementById('modalResult');
|
||||||
|
resEl.innerText = match.has_won ? "WIN" : "LOSS";
|
||||||
|
resEl.className = `text-base font-black mt-0.5 ${match.has_won ? 'text-emerald-400' : 'text-rose-400'}`;
|
||||||
|
|
||||||
|
document.getElementById('modalAgent').innerText = match.agent;
|
||||||
|
document.getElementById('modalKDA').innerText = `${match.kills} / ${match.deaths} / ${match.assists}`;
|
||||||
|
document.getElementById('modalACS').innerText = match.details.combat_score;
|
||||||
|
|
||||||
|
// Hit-Zonen binden
|
||||||
|
document.getElementById('modalHSRate').innerText = match.details.hs_rate;
|
||||||
|
document.getElementById('modalHSBar').style.width = match.details.hs_rate;
|
||||||
|
document.getElementById('modalHitsCount').innerText = `${match.details.headshots} Head / ${match.details.bodyshots} Body / ${match.details.legshots} Legs`;
|
||||||
|
|
||||||
|
// Gefechtsmetriken
|
||||||
|
document.getElementById('modalFB').innerText = match.details.first_bloods;
|
||||||
|
document.getElementById('modalEcon').innerText = match.details.avg_spent;
|
||||||
|
document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Auszeichnung";
|
||||||
|
document.getElementById('modalMulti').innerText = `3K: ${match.details.multikills['3k']} | 4K: ${match.details.multikills['4k']} | Ace: ${match.details.multikills['5k']}`;
|
||||||
|
|
||||||
|
const modal = document.getElementById('matchModal');
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
modal.classList.add('flex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMatchModal() {
|
||||||
|
const modal = document.getElementById('matchModal');
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
modal.classList.remove('flex');
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('searchForm').addEventListener('submit', async function(e) {
|
document.getElementById('searchForm').addEventListener('submit', async function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
@ -99,11 +213,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const [name, tag] = rawInput.split('#').map(p => p.trim());
|
const [name, tag] = rawInput.split('#').map(p => p.trim());
|
||||||
if (!name || !tag) {
|
|
||||||
alert("Name oder Tag unvollständig.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const btn = this.querySelector('button[type="submit"]');
|
const btn = this.querySelector('button[type="submit"]');
|
||||||
btn.innerText = "Analyzing...";
|
btn.innerText = "Analyzing...";
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
|
|
@ -113,14 +222,14 @@
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.status === "success") {
|
if (data.status === "success") {
|
||||||
// Spieler- & Account-Daten binden
|
currentMatchesCache = data.matches; // Cache befüllen für Klick-Aktionen
|
||||||
|
|
||||||
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()}`;
|
||||||
document.getElementById('displayLevel').innerText = data.account.level;
|
document.getElementById('displayLevel').innerText = data.account.level;
|
||||||
document.getElementById('displayRank').innerText = data.rank.current_tier_name;
|
document.getElementById('displayRank').innerText = data.rank.current_tier_name;
|
||||||
document.getElementById('displayRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
document.getElementById('displayRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
||||||
|
|
||||||
// Dynamisches Einbinden des Rang-Bildes
|
|
||||||
const rankImg = document.getElementById('displayRankImage');
|
const rankImg = document.getElementById('displayRankImage');
|
||||||
const rankFallback = document.getElementById('rankFallbackIcon');
|
const rankFallback = document.getElementById('rankFallbackIcon');
|
||||||
if (data.rank.rank_image_url) {
|
if (data.rank.rank_image_url) {
|
||||||
|
|
@ -139,22 +248,19 @@
|
||||||
cardDiv.innerText = '';
|
cardDiv.innerText = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global berechnete Werte füllen
|
|
||||||
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
|
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
|
||||||
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;
|
||||||
|
|
||||||
// Tabellen-Überschrift aktualisieren
|
|
||||||
document.getElementById('matchHistoryHeader').innerText = `Recent Matches (Competitive - Last ${data.calculated_stats.matches_analyzed})`;
|
document.getElementById('matchHistoryHeader').innerText = `Recent Matches (Competitive - Last ${data.calculated_stats.matches_analyzed})`;
|
||||||
|
|
||||||
// Matches-Liste befüllen (Hier wurden alle fehlerhaften Assets entfernt)
|
|
||||||
const historyContainer = document.getElementById('matchHistoryContainer');
|
const historyContainer = document.getElementById('matchHistoryContainer');
|
||||||
historyContainer.innerHTML = '';
|
historyContainer.innerHTML = '';
|
||||||
|
|
||||||
if (data.matches.length === 0) {
|
if (data.matches.length === 0) {
|
||||||
historyContainer.innerHTML = '<p class="text-xs text-slate-500 p-4 text-center">Keine aktuellen Competitive Matches gefunden.</p>';
|
historyContainer.innerHTML = '<p class="text-xs text-slate-500 p-4 text-center">Keine aktuellen Competitive Matches gefunden.</p>';
|
||||||
} else {
|
} else {
|
||||||
data.matches.forEach(match => {
|
data.matches.forEach((match, index) => {
|
||||||
const borderColor = match.has_won ? 'border-emerald-500' : 'border-rose-500';
|
const borderColor = match.has_won ? 'border-emerald-500' : 'border-rose-500';
|
||||||
const textColor = match.has_won ? 'text-emerald-400' : 'text-rose-400';
|
const textColor = match.has_won ? 'text-emerald-400' : 'text-rose-400';
|
||||||
|
|
||||||
|
|
@ -167,8 +273,9 @@
|
||||||
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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Das div hat nun "onclick='openMatchReport(${index})'" und ist als Zeiger-Cursor markiert
|
||||||
const matchHTML = `
|
const matchHTML = `
|
||||||
<div 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-slate-900/90">
|
<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">
|
||||||
<div>
|
<div>
|
||||||
<span class="font-black ${textColor} tracking-wider mr-2">${match.has_won ? 'WIN' : 'LOSS'}</span>
|
<span class="font-black ${textColor} tracking-wider mr-2">${match.has_won ? 'WIN' : 'LOSS'}</span>
|
||||||
<span class="font-bold text-slate-200">${match.score}</span>
|
<span class="font-bold text-slate-200">${match.score}</span>
|
||||||
|
|
@ -189,7 +296,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alle gespielten Agenten ausgeben
|
|
||||||
const agentContainer = document.getElementById('agentContainer');
|
const agentContainer = document.getElementById('agentContainer');
|
||||||
agentContainer.innerHTML = '';
|
agentContainer.innerHTML = '';
|
||||||
if (data.all_agents.length === 0) {
|
if (data.all_agents.length === 0) {
|
||||||
|
|
@ -215,7 +321,7 @@
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert("API-Fehler oder Verbindungsabbruch.");
|
alert("API-Fehler oder Verbindungsabbruch.");
|
||||||
} finally {
|
} finaly {
|
||||||
btn.innerText = "Analyse";
|
btn.innerText = "Analyse";
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1530,7 +1530,6 @@ VALORANT_API_BASE = "https://api.henrikdev.xyz/valorant"
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('view_ayrantracker')
|
@permission_required('view_ayrantracker')
|
||||||
def ayrantracker():
|
def ayrantracker():
|
||||||
# Übergibt das Template im AstraOS-Design
|
|
||||||
return render_template('ayrantracker.html', active_page='ayrantracker')
|
return render_template('ayrantracker.html', active_page='ayrantracker')
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1554,7 +1553,7 @@ def get_valorant_stats(name, tag):
|
||||||
acc_data = acc_res.json().get('data', {}) or {}
|
acc_data = acc_res.json().get('data', {}) or {}
|
||||||
region = acc_data.get("region", "eu")
|
region = acc_data.get("region", "eu")
|
||||||
|
|
||||||
# 2. Aktueller Rang (MMR v1) mit Bild-Pfad Erweiterung
|
# 2. Aktueller Rang (MMR v1)
|
||||||
mmr_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr/{region}/{name}/{tag}", headers=headers, timeout=10)
|
mmr_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr/{region}/{name}/{tag}", headers=headers, timeout=10)
|
||||||
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 = {}
|
||||||
|
|
@ -1570,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 auf size=20 angefordert
|
# 4. Match Historie erhöht 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 []
|
||||||
|
|
@ -1581,7 +1580,6 @@ def get_valorant_stats(name, tag):
|
||||||
total_deaths = 0
|
total_deaths = 0
|
||||||
total_assists = 0
|
total_assists = 0
|
||||||
|
|
||||||
# Struktur für die Erfassung ALLER Agenten-Stats (für KDA)
|
|
||||||
agent_stats = {}
|
agent_stats = {}
|
||||||
processed_matches = []
|
processed_matches = []
|
||||||
|
|
||||||
|
|
@ -1591,7 +1589,7 @@ def get_valorant_stats(name, tag):
|
||||||
match_id = metadata.get('matchid')
|
match_id = metadata.get('matchid')
|
||||||
players = match.get('players', {}).get('all_players', [])
|
players = match.get('players', {}).get('all_players', [])
|
||||||
|
|
||||||
# Fehlertoleranter Spielerabgleich
|
# Spielerabgleich
|
||||||
me = next((p for p in players if
|
me = next((p for p in players if
|
||||||
p.get('name', '').lower() == name.lower() and p.get('tag', '').lower() == tag.lower()), None)
|
p.get('name', '').lower() == name.lower() and p.get('tag', '').lower() == tag.lower()), None)
|
||||||
if not me:
|
if not me:
|
||||||
|
|
@ -1604,12 +1602,13 @@ def get_valorant_stats(name, tag):
|
||||||
m_kills = stats.get('kills', 0) or 0
|
m_kills = stats.get('kills', 0) or 0
|
||||||
m_deaths = stats.get('deaths', 0) or 0
|
m_deaths = stats.get('deaths', 0) or 0
|
||||||
m_assists = stats.get('assists', 0) or 0
|
m_assists = stats.get('assists', 0) or 0
|
||||||
|
m_score = stats.get('score', 0) or 0
|
||||||
|
|
||||||
total_kills += m_kills
|
total_kills += m_kills
|
||||||
total_deaths += m_deaths
|
total_deaths += m_deaths
|
||||||
total_assists += m_assists
|
total_assists += m_assists
|
||||||
|
|
||||||
# Spezifische Werte für diesen Agenten sammeln
|
# Agenten-Statistiken sammeln
|
||||||
if agent_name not in agent_stats:
|
if agent_name not in agent_stats:
|
||||||
agent_stats[agent_name] = {"count": 0, "kills": 0, "deaths": 0, "assists": 0}
|
agent_stats[agent_name] = {"count": 0, "kills": 0, "deaths": 0, "assists": 0}
|
||||||
|
|
||||||
|
|
@ -1628,16 +1627,64 @@ def get_valorant_stats(name, tag):
|
||||||
|
|
||||||
red_rounds = teams.get('red', {}).get('rounds_won', 0) or 0
|
red_rounds = teams.get('red', {}).get('rounds_won', 0) or 0
|
||||||
blue_rounds = teams.get('blue', {}).get('rounds_won', 0) or 0
|
blue_rounds = teams.get('blue', {}).get('rounds_won', 0) or 0
|
||||||
|
rounds_played = red_rounds + blue_rounds
|
||||||
|
|
||||||
if my_team_color == 'red':
|
if my_team_color == 'red':
|
||||||
score_str = f"{red_rounds} : {blue_rounds}"
|
score_str = f"{red_rounds} : {blue_rounds}"
|
||||||
|
enemy_rounds = blue_rounds
|
||||||
|
my_rounds = red_rounds
|
||||||
else:
|
else:
|
||||||
score_str = f"{blue_rounds} : {red_rounds}"
|
score_str = f"{blue_rounds} : {red_rounds}"
|
||||||
|
enemy_rounds = red_rounds
|
||||||
|
my_rounds = blue_rounds
|
||||||
|
|
||||||
|
# --- ERWEITERTE ANANLYSE FÜR DEN DETAIL REPORT ---
|
||||||
|
# Trefferzonen (Head, Body, Legs) aus der API extrahieren
|
||||||
|
economy = me.get('economy', {})
|
||||||
|
spent_spent = economy.get('spent', {}).get('overall', 0) or 0
|
||||||
|
avg_spent = round(spent_spent / rounds_played, 0) if rounds_played > 0 else 0
|
||||||
|
|
||||||
|
# Hit-Zonen auswerten
|
||||||
|
headshots = stats.get('headshots', 0) or 0
|
||||||
|
bodyshots = stats.get('bodyshots', 0) or 0
|
||||||
|
legshots = stats.get('legshots', 0) or 0
|
||||||
|
total_hits = headshots + bodyshots + legshots
|
||||||
|
hs_rate = round((headshots / total_hits) * 100, 1) if total_hits > 0 else 0
|
||||||
|
|
||||||
|
# First Bloods & Multi-Kills aus den Runden-Details filtern
|
||||||
|
first_bloods = 0
|
||||||
|
kills_per_round = {}
|
||||||
|
round_data = match.get('rounds', []) or []
|
||||||
|
|
||||||
|
for r_idx, r in enumerate(round_data):
|
||||||
|
player_stats_round = r.get('player_stats', []) or []
|
||||||
|
# First Blood Check
|
||||||
|
kill_events = r.get('kill_events', []) or []
|
||||||
|
if kill_events:
|
||||||
|
first_kill = kill_events[0]
|
||||||
|
if first_kill.get('killer_name', '').lower() == name.lower():
|
||||||
|
first_bloods += 1
|
||||||
|
|
||||||
|
# Multi-Kills Check
|
||||||
|
for ps in player_stats_round:
|
||||||
|
if ps.get('player_name', '').lower() == name.lower():
|
||||||
|
k_count = ps.get('kills', 0) or 0
|
||||||
|
if k_count > 0:
|
||||||
|
kills_per_round[k_count] = kills_per_round.get(k_count, 0) + 1
|
||||||
|
|
||||||
|
# Team MVP bestimmen
|
||||||
|
is_team_mvp = True
|
||||||
|
for p in players:
|
||||||
|
if p.get('team', '').lower() == my_team_color:
|
||||||
|
if (p.get('stats', {}).get('score', 0) or 0) > m_score:
|
||||||
|
is_team_mvp = False
|
||||||
|
|
||||||
mmr_change = rr_history.get(match_id, 0) if match_mode == 'competitive' else None
|
mmr_change = rr_history.get(match_id, 0) if match_mode == 'competitive' else None
|
||||||
map_name = metadata.get('map', 'Unknown')
|
map_name = metadata.get('map', 'Unknown')
|
||||||
|
game_length_min = round((metadata.get('game_length', 0) or 0) / 60, 1)
|
||||||
|
|
||||||
processed_matches.append({
|
processed_matches.append({
|
||||||
|
"match_id": match_id,
|
||||||
"map": map_name,
|
"map": map_name,
|
||||||
"mode": metadata.get('mode', 'Unknown'),
|
"mode": metadata.get('mode', 'Unknown'),
|
||||||
"agent": agent_name,
|
"agent": agent_name,
|
||||||
|
|
@ -1646,14 +1693,31 @@ def get_valorant_stats(name, tag):
|
||||||
"assists": m_assists,
|
"assists": m_assists,
|
||||||
"score": score_str,
|
"score": score_str,
|
||||||
"has_won": has_won,
|
"has_won": has_won,
|
||||||
"mmr_change": mmr_change
|
"mmr_change": mmr_change,
|
||||||
|
# Detail-Statistiken für Klick-Event
|
||||||
|
"details": {
|
||||||
|
"game_length": f"{game_length_min} Min",
|
||||||
|
"server": metadata.get('cluster', 'EU'),
|
||||||
|
"headshots": headshots,
|
||||||
|
"bodyshots": bodyshots,
|
||||||
|
"legshots": legshots,
|
||||||
|
"hs_rate": f"{hs_rate}%",
|
||||||
|
"combat_score": m_score,
|
||||||
|
"avg_spent": f"{int(avg_spent)} ¥",
|
||||||
|
"first_bloods": first_bloods,
|
||||||
|
"is_team_mvp": is_team_mvp,
|
||||||
|
"multikills": {
|
||||||
|
"3k": kills_per_round.get(3, 0),
|
||||||
|
"4k": kills_per_round.get(4, 0),
|
||||||
|
"5k": kills_per_round.get(5, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
# Berechnungen für globale Stats
|
# Berechnungen für globale 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
|
||||||
|
|
||||||
# Alle Agenten verarbeiten & Best Agent ermitteln (nach KDA)
|
|
||||||
all_agents = []
|
all_agents = []
|
||||||
best_agent_name = "Keiner"
|
best_agent_name = "Keiner"
|
||||||
highest_agent_kda = -1.0
|
highest_agent_kda = -1.0
|
||||||
|
|
@ -1662,8 +1726,6 @@ def get_valorant_stats(name, tag):
|
||||||
a_kills = data["kills"]
|
a_kills = data["kills"]
|
||||||
a_deaths = data["deaths"]
|
a_deaths = data["deaths"]
|
||||||
a_assists = data["assists"]
|
a_assists = data["assists"]
|
||||||
|
|
||||||
# KDA-Formel: (Kills + Assists) / Deaths
|
|
||||||
a_kda = round((a_kills + a_assists) / a_deaths, 2) if a_deaths > 0 else float(a_kills + a_assists)
|
a_kda = round((a_kills + a_assists) / a_deaths, 2) if a_deaths > 0 else float(a_kills + a_assists)
|
||||||
|
|
||||||
all_agents.append({
|
all_agents.append({
|
||||||
|
|
@ -1676,7 +1738,6 @@ def get_valorant_stats(name, tag):
|
||||||
highest_agent_kda = a_kda
|
highest_agent_kda = a_kda
|
||||||
best_agent_name = name_key
|
best_agent_name = name_key
|
||||||
|
|
||||||
# Sortiere die Liste nach der Anzahl der Spiele (Häufigkeit)
|
|
||||||
all_agents = sorted(all_agents, key=lambda x: x["count"], reverse=True)
|
all_agents = sorted(all_agents, key=lambda x: x["count"], reverse=True)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue