feat: Add recent performance stability stats (matches/days) to player profile
This commit is contained in:
135
web/routes/matches.py
Normal file
135
web/routes/matches.py
Normal file
@@ -0,0 +1,135 @@
|
||||
from flask import Blueprint, render_template, request, Response
|
||||
from web.services.stats_service import StatsService
|
||||
from web.config import Config
|
||||
import json
|
||||
|
||||
bp = Blueprint('matches', __name__, url_prefix='/matches')
|
||||
|
||||
@bp.route('/')
|
||||
def index():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
map_name = request.args.get('map')
|
||||
date_from = request.args.get('date_from')
|
||||
|
||||
# Fetch summary stats (for the dashboard)
|
||||
summary_stats = StatsService.get_team_stats_summary()
|
||||
|
||||
matches, total = StatsService.get_matches(page, Config.ITEMS_PER_PAGE, map_name, date_from)
|
||||
total_pages = (total + Config.ITEMS_PER_PAGE - 1) // Config.ITEMS_PER_PAGE
|
||||
|
||||
return render_template('matches/list.html',
|
||||
matches=matches, total=total, page=page, total_pages=total_pages,
|
||||
summary_stats=summary_stats)
|
||||
|
||||
@bp.route('/<match_id>')
|
||||
def detail(match_id):
|
||||
match = StatsService.get_match_detail(match_id)
|
||||
if not match:
|
||||
return "Match not found", 404
|
||||
|
||||
players = StatsService.get_match_players(match_id)
|
||||
# Convert sqlite3.Row objects to dicts to allow modification
|
||||
players = [dict(p) for p in players]
|
||||
|
||||
rounds = StatsService.get_match_rounds(match_id)
|
||||
|
||||
# --- Roster Identification ---
|
||||
# Fetch active roster to identify "Our Team" players
|
||||
from web.services.web_service import WebService
|
||||
lineups = WebService.get_lineups()
|
||||
# Assume we use the first/active lineup
|
||||
active_roster_ids = []
|
||||
if lineups:
|
||||
try:
|
||||
active_roster_ids = json.loads(lineups[0]['player_ids_json'])
|
||||
except:
|
||||
pass
|
||||
|
||||
# Mark roster players (Ensure strict string comparison)
|
||||
roster_set = set(str(uid) for uid in active_roster_ids)
|
||||
for p in players:
|
||||
p['is_in_roster'] = str(p['steam_id_64']) in roster_set
|
||||
|
||||
# --- Party Size Calculation ---
|
||||
# Only calculate party size for OUR ROSTER members.
|
||||
# Group roster members by match_team_id
|
||||
roster_parties = {} # match_team_id -> count of roster members
|
||||
|
||||
for p in players:
|
||||
if p['is_in_roster']:
|
||||
mtid = p.get('match_team_id')
|
||||
if mtid and mtid > 0:
|
||||
key = f"tid_{mtid}"
|
||||
roster_parties[key] = roster_parties.get(key, 0) + 1
|
||||
|
||||
# Assign party size ONLY to roster members
|
||||
for p in players:
|
||||
if p['is_in_roster']:
|
||||
mtid = p.get('match_team_id')
|
||||
if mtid and mtid > 0:
|
||||
p['party_size'] = roster_parties.get(f"tid_{mtid}", 1)
|
||||
else:
|
||||
p['party_size'] = 1 # Solo roster player
|
||||
else:
|
||||
p['party_size'] = 0 # Hide party info for non-roster players
|
||||
|
||||
# Organize players by Side (team_id)
|
||||
# team_id 1 = Team 1, team_id 2 = Team 2
|
||||
# Note: group_id 1/2 usually corresponds to Team 1/2.
|
||||
# Fallback to team_id if group_id is missing or 0 (legacy data compatibility)
|
||||
team1_players = [p for p in players if p.get('group_id') == 1]
|
||||
team2_players = [p for p in players if p.get('group_id') == 2]
|
||||
|
||||
# If group_id didn't work (empty lists), try team_id grouping (if team_id is 1/2 only)
|
||||
if not team1_players and not team2_players:
|
||||
team1_players = [p for p in players if p['team_id'] == 1]
|
||||
team2_players = [p for p in players if p['team_id'] == 2]
|
||||
|
||||
# Explicitly sort by Rating DESC
|
||||
team1_players.sort(key=lambda x: x.get('rating', 0) or 0, reverse=True)
|
||||
team2_players.sort(key=lambda x: x.get('rating', 0) or 0, reverse=True)
|
||||
|
||||
# New Data for Enhanced Detail View
|
||||
h2h_stats = StatsService.get_head_to_head_stats(match_id)
|
||||
round_details = StatsService.get_match_round_details(match_id)
|
||||
|
||||
# Convert H2H stats to a more usable format (nested dict)
|
||||
# h2h_matrix[attacker_id][victim_id] = kills
|
||||
h2h_matrix = {}
|
||||
if h2h_stats:
|
||||
for row in h2h_stats:
|
||||
a_id = row['attacker_steam_id']
|
||||
v_id = row['victim_steam_id']
|
||||
kills = row['kills']
|
||||
if a_id not in h2h_matrix: h2h_matrix[a_id] = {}
|
||||
h2h_matrix[a_id][v_id] = kills
|
||||
|
||||
# Create a mapping of SteamID -> Username for the template
|
||||
# We can use the players list we already have
|
||||
player_name_map = {}
|
||||
for p in players:
|
||||
sid = p.get('steam_id_64')
|
||||
name = p.get('username')
|
||||
if sid and name:
|
||||
player_name_map[str(sid)] = name
|
||||
|
||||
return render_template('matches/detail.html', match=match,
|
||||
team1_players=team1_players, team2_players=team2_players,
|
||||
rounds=rounds,
|
||||
h2h_matrix=h2h_matrix,
|
||||
round_details=round_details,
|
||||
player_name_map=player_name_map)
|
||||
|
||||
@bp.route('/<match_id>/raw')
|
||||
def raw_json(match_id):
|
||||
match = StatsService.get_match_detail(match_id)
|
||||
if not match:
|
||||
return "Match not found", 404
|
||||
|
||||
# Construct a raw object from available raw fields
|
||||
data = {
|
||||
'round_list': json.loads(match['round_list_raw']) if match['round_list_raw'] else None,
|
||||
'leetify_data': json.loads(match['leetify_data_raw']) if match['leetify_data_raw'] else None
|
||||
}
|
||||
|
||||
return Response(json.dumps(data, indent=2, ensure_ascii=False), mimetype='application/json')
|
||||
Reference in New Issue
Block a user