Files
yrtv/web/routes/matches.py

136 lines
5.2 KiB
Python

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')