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

+
+
+ + +
+
+ + +
+ +
+
+ + +
+ + +{% 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.")