combining league jsons

This commit is contained in:
bl3kunja-FW
2025-11-14 17:03:30 +01:00
parent aa01f4136d
commit 27e8b31ae0
9 changed files with 1231 additions and 14 deletions
+336 -2
View File
@@ -1087,7 +1087,21 @@ def results_display():
translations=get_translations(),
current_language=get_current_language())
# Priority 1.5: Check if current results are from a finished league (even if league state was archived)
# Priority 1.5: Check if results contain league_data (from league preview/combiner)
elif results and results.get('league_data'):
league_data = results.get('league_data')
calculate_league_final_scores(league_data)
participants = get_league_final_rankings(league_data)
return render_template('league_scoreboard_display.html',
league=league_data,
participants=participants,
results=None,
preview_mode=True,
translations=get_translations(),
current_language=get_current_language())
# Priority 1.6: Check if current results are from a finished league (even if league state was archived)
elif results and results.get('league_tournament_number'):
# This is a league tournament result, but league state was archived
# Try to find the archived league data
@@ -1697,7 +1711,327 @@ def get_league():
return jsonify(league_state)
else:
return jsonify({'status': 'error', 'message': 'No league found'}), 404
@app.route('/league/combine')
def league_combine_page():
"""Page for combining multiple league JSON files"""
if is_mobile_device():
return redirect('/mobile')
return render_template('league_combine.html',
translations=get_translations(),
current_language=get_current_language())
@app.route('/league/preview')
def league_preview():
"""Display league preview from session"""
# Get league data from session
league_data = session.get('preview_league')
if not league_data:
return redirect('/league/combine')
# Calculate scores and get rankings
calculate_league_final_scores(league_data)
participants = get_league_final_rankings(league_data)
return render_template('league_scoreboard_display.html',
league=league_data,
participants=participants,
results=None,
preview_mode=True,
translations=get_translations(),
current_language=get_current_language())
@app.route('/league/set-preview', methods=['POST'])
def set_league_preview():
"""Store league data in session for preview"""
try:
data = request.get_json()
combined_league = data.get('league')
if not combined_league:
return jsonify({'status': 'error', 'message': 'No league data provided'}), 400
# Store in session
session['preview_league'] = combined_league
return jsonify({
'status': 'success',
'redirect_url': '/league/preview'
})
except Exception as e:
print(f"Error setting league preview: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/api/league/combine', methods=['POST'])
def combine_leagues():
"""API endpoint to combine multiple league files"""
try:
data = request.get_json()
leagues = data.get('leagues', [])
if len(leagues) < 1:
return jsonify({'status': 'error', 'message': 'Need at least 1 league'}), 400
# If only one league, just return it for preview
if len(leagues) == 1:
league = leagues[0]
calculate_league_final_scores(league)
participants = get_league_final_rankings(league)
highest_score = max((p['final_score'] for p in participants), default=0)
avg_score = sum(p['final_score'] for p in participants) / len(participants) if participants else 0
return jsonify({
'status': 'success',
'combined_league': league,
'participants': participants,
'source_count': 1,
'tournament_type': league.get('tournament_type', '20_targets'),
'total_participants': len(participants),
'total_tournaments': league.get('total_tournaments', 5),
'highest_score': highest_score,
'avg_score': round(avg_score, 2)
})
# Get tournament type from first league
tournament_type = leagues[0].get('tournament_type', '20_targets')
# Create combined league structure
combined_league = {
'league_id': f'combined_{datetime.now().strftime("%Y%m%d_%H%M%S")}',
'created_at': datetime.now().isoformat(),
'tournament_type': tournament_type,
'total_tournaments': sum(len(league.get('completed_tournaments', [])) for league in leagues),
'current_tournament': 0,
'participants': {},
'completed_tournaments': [],
'league_finished': True,
'combined_from': len(leagues)
}
# Build name-to-player mapping for combining by name
name_to_combined_id = {} # Maps player name to their ID in combined league
next_player_id = 1
# Combine tournament results from all leagues
tournament_counter = 0
for league_idx, league in enumerate(leagues):
# Process each participant in this league
for player_id, league_participant in league.get('participants', {}).items():
player_name = league_participant.get('name', f'Player {player_id}')
# Check if we've seen this player name before
if player_name in name_to_combined_id:
# Use existing combined player
combined_id = name_to_combined_id[player_name]
else:
# Create new combined player
combined_id = str(next_player_id)
next_player_id += 1
name_to_combined_id[player_name] = combined_id
# Initialize new participant
combined_league['participants'][combined_id] = {
'name': player_name,
'joker_used': False,
'tournament_results': [],
'total_score': 0,
'final_score': 0,
'tournaments_participated': 0
}
combined_participant = combined_league['participants'][combined_id]
# Add all tournament results from this league
for result in league_participant.get('tournament_results', []):
combined_participant['tournament_results'].append({
'tournament': tournament_counter + result.get('tournament', 0),
'score': result.get('score', 0),
'tens_count': result.get('tens_count', 0),
'participated': result.get('participated', True),
'source_league': league_idx + 1
})
if result.get('participated', True):
combined_participant['tournaments_participated'] += 1
combined_participant['total_score'] += result.get('score', 0)
# Add completed tournaments
for completed in league.get('completed_tournaments', []):
combined_league['completed_tournaments'].append({
**completed,
'source_league': league_idx + 1
})
tournament_counter += len(league.get('completed_tournaments', []))
# Calculate final scores
calculate_league_final_scores(combined_league)
# Get rankings
participants = get_league_final_rankings(combined_league)
# Calculate stats
highest_score = max((p['final_score'] for p in participants), default=0)
avg_score = sum(p['final_score'] for p in participants) / len(participants) if participants else 0
return jsonify({
'status': 'success',
'combined_league': combined_league,
'participants': participants,
'source_count': len(leagues),
'tournament_type': tournament_type,
'total_participants': len(participants),
'total_tournaments': combined_league['total_tournaments'],
'highest_score': highest_score,
'avg_score': round(avg_score, 2)
})
except Exception as e:
print(f"Error combining leagues: {e}")
import traceback
traceback.print_exc()
return jsonify({'status': 'error', 'message': str(e)}), 400
@app.route('/api/league/convert', methods=['POST'])
def convert_tournaments_to_league():
"""API endpoint to convert 1-5 tournament files into a league"""
try:
data = request.get_json()
tournaments = data.get('tournaments', [])
if len(tournaments) < 1 or len(tournaments) > 5:
return jsonify({'status': 'error', 'message': 'Need 1-5 tournament files'}), 400
# Sort tournaments by finished_at timestamp to maintain chronological order
tournaments.sort(key=lambda t: t.get('results', {}).get('finished_at', ''))
# Get tournament type from first tournament
tournament_type = tournaments[0].get('results', {}).get('tournament_type', '20_targets')
num_tournaments = len(tournaments)
# Collect all unique participants
all_player_ids = set()
for tournament in tournaments:
results = tournament.get('results', {})
all_player_ids.update(results.get('participants', {}).keys())
# Create league structure
created_league = {
'league_id': f'converted_{datetime.now().strftime("%Y%m%d_%H%M%S")}',
'created_at': datetime.now().isoformat(),
'tournament_type': tournament_type,
'total_tournaments': 5, # Always 5 for a full league
'current_tournament': num_tournaments, # How many completed so far
'participants': {},
'completed_tournaments': [],
'league_finished': num_tournaments >= 5, # Only finished if all 5 uploaded
'converted_from_tournaments': True,
'is_partial': num_tournaments < 5
}
# Initialize participants
for player_id in all_player_ids:
created_league['participants'][player_id] = {
'name': '',
'joker_used': False,
'tournament_results': [],
'total_score': 0,
'final_score': 0,
'tournaments_participated': 0
}
# Process each tournament
for tournament_idx, tournament in enumerate(tournaments):
results = tournament.get('results', {})
tournament_results_data = results.get('participants', {})
# Add completed tournament metadata
created_league['completed_tournaments'].append({
'tournament_number': tournament_idx + 1,
'tournament_type': results.get('tournament_type', tournament_type),
'finished_at': results.get('finished_at', datetime.now().isoformat()),
'results_summary': {
'participants': len(tournament_results_data),
'tournament_id': tournament.get('tournament', {}).get('tournament_id', f'tournament_{tournament_idx + 1}')
}
})
# Add results for each participant
for player_id in all_player_ids:
league_participant = created_league['participants'][player_id]
if player_id in tournament_results_data:
participant_data = tournament_results_data[player_id]
# Set name if not set
if not league_participant['name']:
league_participant['name'] = participant_data.get('name', f'Player {player_id}')
# Count tens
tens_count = 0
targets = participant_data.get('targets', {})
for target in targets.values():
for shot_key, shot_value in target.items():
if shot_key.startswith('shot') and shot_value == 10:
tens_count += 1
# Add tournament result
score = participant_data.get('total_score', 0)
league_participant['tournament_results'].append({
'tournament': tournament_idx + 1,
'score': score,
'tens_count': tens_count,
'participated': True
})
league_participant['tournaments_participated'] += 1
league_participant['total_score'] += score
else:
# Player didn't participate (used joker)
league_participant['tournament_results'].append({
'tournament': tournament_idx + 1,
'score': 0,
'tens_count': 0,
'participated': False,
'joker': True
})
if tournament_idx == 0:
# Set joker_used for players who didn't participate in first tournament
league_participant['joker_used'] = True
# Calculate final scores using league rules
calculate_league_final_scores(created_league)
# Get rankings
participants = get_league_final_rankings(created_league)
# Calculate stats
highest_score = max((p['final_score'] for p in participants), default=0)
avg_score = sum(p['final_score'] for p in participants) / len(participants) if participants else 0
return jsonify({
'status': 'success',
'combined_league': created_league,
'participants': participants,
'source_count': num_tournaments,
'tournament_type': tournament_type,
'total_participants': len(participants),
'total_tournaments': num_tournaments,
'is_partial': num_tournaments < 5,
'highest_score': highest_score,
'avg_score': round(avg_score, 2)
})
except Exception as e:
print(f"Error converting tournaments to league: {e}")
import traceback
traceback.print_exc()
return jsonify({'status': 'error', 'message': str(e)}), 400
# Add this route to your Flask app (around line 850, with the other mobile routes)
@app.route('/mobile/remote')