diff --git a/AstraOS/.env b/AstraOS/.env
index 39bcb1c..a5a8358 100644
--- a/AstraOS/.env
+++ b/AstraOS/.env
@@ -5,15 +5,15 @@ SSH_USER='astraos'
SSH_PASS='iwkms@1812:('
VPNAPI_KEY='015ada9472664329affb2f26d7036d47'
-# Discord OAuth2 Credentials
DISCORD_CLIENT_ID='1395018660267036712'
DISCORD_CLIENT_SECRET='QVGmwtTDsuE8mh2YlBMqeHndeRRKW9-a'
DISCORD_BOT_TOKEN='MTM5NTAxODY2MDI2NzAzNjcxMg.GJE-k4.W0o09yJZfG3onzyzHLbXu4vBrKPXFS1IVuzhMA'
DISCORD_REDIRECT_URI='https://astra-os.de/callback/discord'
-# Impressum (vom Benutzer bereitgestellt)
IMPRESSUM_NAME='Elias Geworski'
IMPRESSUM_ADDRESS='Taiostraße 4b, 90562 Heroldsberg'
IMPRESSUM_EMAIL='elias.gew@hotmail.com'
IMPRESSUM_PHONE=''
IMPRESSUM_COMPANY_REG=''
+
+VALORANT_API_KEY=HDEV-1dbf4057-a238-4e2f-805d-f9b268b101e2
diff --git a/AstraOS/Frontend/HTML/ayrantracker.html b/AstraOS/Frontend/HTML/ayrantracker.html
new file mode 100644
index 0000000..10d4206
--- /dev/null
+++ b/AstraOS/Frontend/HTML/ayrantracker.html
@@ -0,0 +1,140 @@
+{% extends "sidebar.html" %}
+
+{% block title %}AstraOS — AyranTracker{% endblock %}
+
+{% block content %}
+
+
+
+ AYRANTRACKER
+
+ Professional Valorant Analytics für AstraOS
+
+
+
+
Spieler-Analyse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![Player Card]()
+
Loading...
+
Level: --
+
+
+
Aktueller Rang
+
Unranked
+
0 RR
+
+
+
+
+
Berechnete Performance (Letzte Matches)
+
+
+
+ Winrate
+ 0%
+
+
+ K/D Ratio
+ 0.0
+
+
+ Ø Schaden / Runde (ADR)
+ 0.0
+
+
+ Analysierte Matches
+ 0
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/AstraOS/Frontend/HTML/sidebar.html b/AstraOS/Frontend/HTML/sidebar.html
index 3f9355d..a278b32 100644
--- a/AstraOS/Frontend/HTML/sidebar.html
+++ b/AstraOS/Frontend/HTML/sidebar.html
@@ -272,6 +272,16 @@
🚚 ETS2 DLCs
{% endif %}
+ {% if 'view_ayrantracker' in session.get('permissions', []) %}
+
+ 🥛 AyranTracker
+
+ {% endif %}
{% if not private_tools.has_access %}
Du hast nicht genügend Berechtigungen für diesen Bereich.
diff --git a/AstraOS/astra_os.py b/AstraOS/astra_os.py
index a92afa0..1067285 100644
--- a/AstraOS/astra_os.py
+++ b/AstraOS/astra_os.py
@@ -91,7 +91,8 @@ try:
"instranet",
"view_ip_analyzer",
"view_age_verification",
- "manage_age_verification"
+ "manage_age_verification",
+ "view_ayrantracker"
]
if roles_collection.count_documents({}) == 0:
print("WARNUNG: Keine Rollen in der Datenbank gefunden. Erstelle Standard-Rollen...")
@@ -1520,6 +1521,117 @@ def update_maintenance():
def page_not_found(e):
return render_template('404.html'), 404
+VALORANT_API_KEY = os.getenv("VALORANT_API_KEY", "")
+VALORANT_API_BASE = "https://api.henrikdev.xyz/valorant"
+
+
+@app.route('/tools/ayrantracker')
+@login_required
+@permission_required('view_ayrantracker')
+def ayrantracker():
+ return render_template('ayrantracker.html', active_page='ayrantracker')
+
+
+@app.route('/api/v1/profile//', methods=['GET'])
+@login_required
+@permission_required('view_ayrantracker')
+def get_valorant_stats(name, tag):
+ # Sicherheitsprüfung, falls du vergessen hast, den Key in die .env einzutragen
+ if not VALORANT_API_KEY:
+ return jsonify({"status": "error", "message": "API-Key Konfiguration fehlt in der .env-Datei."}), 500
+
+ headers = {"Authorization": VALORANT_API_KEY}
+
+ try:
+ acc_res = requests.get(f"{VALORANT_API_BASE}/v1/account/{name}/{tag}?force=true", headers=headers, timeout=10)
+ if acc_res.status_code != 200:
+ return jsonify(
+ {"status": "error", "message": "Spieler nicht gefunden oder API-Limit erreicht."}), acc_res.status_code
+
+ acc_data = acc_res.json().get('data', {}) or {}
+ region = acc_data.get("region", "eu")
+
+ 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 {}
+ if not mmr_data: mmr_data = {}
+
+ matches_res = requests.get(f"{VALORANT_API_BASE}/v3/matches/{region}/{name}/{tag}?size=15&mode=competitive",
+ headers=headers, timeout=10)
+ matches_list = matches_res.json().get('data', []) if matches_res.status_code == 200 else []
+ if not matches_list: matches_list = []
+
+ match_count = len(matches_list)
+ wins = 0
+ total_kills = 0
+ total_deaths = 0
+ total_damage = 0
+ total_rounds = 0
+ agent_counts = {}
+
+ for match in matches_list:
+ players = match.get('players', {}).get('all_players', [])
+ me = next((p for p in players if
+ p.get('name', '').lower() == name.lower() and p.get('tag', '').lower() == tag.lower()), None)
+ if not me:
+ continue
+
+ agent_name = me.get('character', 'Unknown')
+ agent_counts[agent_name] = agent_counts.get(agent_name, 0) + 1
+
+ stats = me.get('stats', {})
+ total_kills += stats.get('kills', 0)
+ total_deaths += stats.get('deaths', 0)
+
+ teams = match.get('teams', {})
+ my_team_color = me.get('team', '').lower()
+ my_team_data = teams.get(my_team_color, {})
+
+ if my_team_data.get('has_won') is True:
+ wins += 1
+
+ rounds_played = (teams.get('red', {}).get('rounds_won', 0) or 0) + (
+ teams.get('blue', {}).get('rounds_won', 0) or 0)
+ total_rounds += rounds_played
+
+ round_data = match.get('rounds', [])
+ for r in round_data:
+ player_stats = r.get('player_stats', [])
+ p_round_stat = next((ps for ps in player_stats if ps.get('player_name', '').lower() == name.lower()),
+ None)
+ if p_round_stat:
+ total_damage += p_round_stat.get('damage', 0)
+
+ 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
+ adr_calculated = round(total_damage / total_rounds, 1) if total_rounds > 0 else 0
+
+ sorted_agents = sorted(agent_counts.items(), key=lambda x: x[1], reverse=True)
+ top_agents = [{"name": a[0], "count": a[1]} for a in sorted_agents[:2]]
+
+ return jsonify({
+ "status": "success",
+ "account": {
+ "name": acc_data.get('name'),
+ "tag": acc_data.get('tag'),
+ "level": acc_data.get('account_level'),
+ "card_url": acc_data.get('card', {}).get('small') if acc_data.get('card') else None
+ },
+ "rank": {
+ "current_tier_name": mmr_data.get('currenttierpatched', 'Unranked') or 'Unranked',
+ "ranking_in_tier": mmr_data.get('ranking_in_tier', 0) or 0,
+ },
+ "calculated_stats": {
+ "win_rate": f"{winrate_calculated}%",
+ "kd_ratio": str(kd_calculated),
+ "avg_damage_round": str(adr_calculated),
+ "matches_analyzed": match_count
+ },
+ "top_agents": top_agents
+ })
+
+ except Exception as e:
+ return jsonify({"status": "error", "message": f"Interner Fehler: {str(e)}"}), 500
+
if __name__ == '__main__':
app.config['SESSION_COOKIE_SECURE'] = False
print("INFO: Starte den Server im Entwicklungsmodus ohne HTTPS.")