252 lines
12 KiB
Python
252 lines
12 KiB
Python
from flask import Flask, render_template, jsonify
|
|
from datetime import datetime
|
|
import os
|
|
import sys
|
|
import traceback
|
|
from services.sleeper_api import SleeperAPI
|
|
from services.espn_api import ESPNAPI
|
|
from config import Config
|
|
|
|
# Force unbuffered output for Docker logs
|
|
os.environ['PYTHONUNBUFFERED'] = '1'
|
|
|
|
print("=== FantasyCron Starting ===", flush=True)
|
|
print(f"=== Version: {Config.VERSION} ===", flush=True)
|
|
|
|
app = Flask(__name__)
|
|
app.config.from_object(Config)
|
|
|
|
# Initialize API services
|
|
sleeper_api = SleeperAPI()
|
|
espn_api = ESPNAPI()
|
|
|
|
def get_league_color(league_index):
|
|
"""Assign colors to leagues in order"""
|
|
colors = app.config['LEAGUE_COLORS']
|
|
return colors[league_index % len(colors)] # Cycle through colors
|
|
|
|
@app.context_processor
|
|
def inject_apis():
|
|
"""Make API and version available to all templates"""
|
|
return dict(sleeper_api=sleeper_api, app_version=app.config['VERSION'])
|
|
|
|
@app.route('/')
|
|
def index():
|
|
"""Home page with username input"""
|
|
print("DEBUG: Index route accessed", flush=True)
|
|
return render_template('index.html')
|
|
|
|
@app.route('/<username>')
|
|
def dashboard_current(username):
|
|
"""Dashboard for current NFL week"""
|
|
print(f"DEBUG: Dashboard current route - username: '{username}'", flush=True)
|
|
try:
|
|
nfl_state = sleeper_api.get_nfl_state()
|
|
current_week = nfl_state.get('display_week', 1)
|
|
print(f"DEBUG: Current week: {current_week}", flush=True)
|
|
return dashboard(username, current_week)
|
|
except Exception as e:
|
|
print(f"ERROR: dashboard_current exception - {str(e)}", flush=True)
|
|
print(f"ERROR: Full traceback: {traceback.format_exc()}", flush=True)
|
|
return render_template('error.html',
|
|
message=f"Could not find user '{username}'. Please check the username and try again.")
|
|
|
|
@app.route('/<username>/<int:week>')
|
|
def dashboard_week(username, week):
|
|
"""Dashboard for specific week"""
|
|
print(f"DEBUG: Dashboard week - username: '{username}', week: {week}", flush=True)
|
|
return dashboard(username, week)
|
|
|
|
def dashboard(username, week):
|
|
"""Main dashboard logic - fetch and display user's fantasy data"""
|
|
print(f"DEBUG: Dashboard function START - username: '{username}', week: {week}", flush=True)
|
|
try:
|
|
# Get user info from Sleeper
|
|
print(f"DEBUG: Calling get_user() with username: '{username}'", flush=True)
|
|
user = sleeper_api.get_user(username)
|
|
print(f"DEBUG: get_user() returned: {user}", flush=True)
|
|
|
|
if not user:
|
|
print(f"WARNING: User lookup failed for username: '{username}'", flush=True)
|
|
return render_template('error.html',
|
|
message=f"Could not find user '{username}'. Please check the username and try again.")
|
|
|
|
print(f"DEBUG: User found - ID: {user.get('user_id')}, Display: {user.get('display_name', 'Unknown')}", flush=True)
|
|
|
|
# Get current NFL season
|
|
print("DEBUG: Calling get_nfl_state()", flush=True)
|
|
nfl_state = sleeper_api.get_nfl_state()
|
|
season = nfl_state.get('season', str(datetime.now().year))
|
|
print(f"DEBUG: Using season: {season}", flush=True)
|
|
|
|
# Get user's fantasy leagues
|
|
user_id = user['user_id']
|
|
print(f"DEBUG: Calling get_user_leagues() with user_id: '{user_id}', season: '{season}'", flush=True)
|
|
leagues = sleeper_api.get_user_leagues(user_id, season)
|
|
print(f"DEBUG: Found {len(leagues) if leagues else 0} leagues", flush=True)
|
|
|
|
if leagues:
|
|
for i, league in enumerate(leagues):
|
|
print(f"DEBUG: League {i+1}: ID={league.get('league_id')}, Name='{league.get('name')}'", flush=True)
|
|
|
|
# Get NFL game schedule for the week
|
|
print(f"DEBUG: Calling get_week_schedule() for week {week}, season {season}", flush=True)
|
|
try:
|
|
schedule = espn_api.get_week_schedule(week, season)
|
|
print(f"DEBUG: Schedule retrieved successfully", flush=True)
|
|
except Exception as e:
|
|
print(f"ERROR: ESPN schedule fetch failed: {str(e)}", flush=True)
|
|
schedule = {}
|
|
|
|
# Process each league for matchup data
|
|
league_data = []
|
|
for i, league in enumerate(leagues):
|
|
print(f"DEBUG: ===== Processing league {i+1}/{len(leagues)}: '{league['name']}' =====", flush=True)
|
|
league_id = league['league_id']
|
|
|
|
try:
|
|
# Get matchups for the current week
|
|
print(f"DEBUG: Calling get_matchups() for league {league_id}, week {week}", flush=True)
|
|
matchups = sleeper_api.get_matchups(league_id, week)
|
|
print(f"DEBUG: Found {len(matchups) if matchups else 0} matchups", flush=True)
|
|
|
|
# Get rosters to find user's team
|
|
print(f"DEBUG: Calling get_rosters() for league {league_id}", flush=True)
|
|
rosters = sleeper_api.get_rosters(league_id)
|
|
print(f"DEBUG: Found {len(rosters) if rosters else 0} rosters", flush=True)
|
|
|
|
# Find user's roster in this league
|
|
user_roster = next((r for r in rosters if r['owner_id'] == user['user_id']), None)
|
|
print(f"DEBUG: User roster found: {user_roster is not None}", flush=True)
|
|
|
|
if user_roster and matchups:
|
|
# Find user's matchup for this week
|
|
user_matchup = next((m for m in matchups if m['roster_id'] == user_roster['roster_id']), None)
|
|
print(f"DEBUG: User matchup found: {user_matchup is not None}", flush=True)
|
|
|
|
# Find opponent's matchup and user info
|
|
opponent_matchup = None
|
|
opponent_user = None
|
|
if user_matchup:
|
|
# Find opponent in same matchup
|
|
opponent_matchup = next((m for m in matchups if m['matchup_id'] == user_matchup['matchup_id'] and m['roster_id'] != user_roster['roster_id']), None)
|
|
print(f"DEBUG: Opponent matchup found: {opponent_matchup is not None}", flush=True)
|
|
|
|
if opponent_matchup:
|
|
# Get opponent's roster to find owner
|
|
opponent_roster = next((r for r in rosters if r['roster_id'] == opponent_matchup['roster_id']), None)
|
|
if opponent_roster:
|
|
opponent_owner_id = opponent_roster['owner_id']
|
|
# Fetch opponent's user profile
|
|
opponent_user = sleeper_api.get_user_by_id(opponent_owner_id)
|
|
print(f"DEBUG: Opponent user: {opponent_user.get('display_name') if opponent_user else 'None'}", flush=True)
|
|
|
|
# Get all players on user's roster for calendar
|
|
all_players = []
|
|
if user_roster and user_roster.get('players'):
|
|
players_list = user_roster['players']
|
|
print(f"DEBUG: Processing {len(players_list)} total players for calendar", flush=True)
|
|
|
|
for player_id in players_list:
|
|
try:
|
|
# Get player details from Sleeper API
|
|
player = sleeper_api.get_player_info(player_id)
|
|
if player:
|
|
all_players.append(player)
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to get player info for {player_id}: {str(e)}", flush=True)
|
|
|
|
# Store processed league data
|
|
league_info = {
|
|
'league': league,
|
|
'league_color': get_league_color(i), # Assign color by order
|
|
'user_matchup': user_matchup,
|
|
'opponent_matchup': opponent_matchup,
|
|
'opponent_user': opponent_user,
|
|
'user_roster': user_roster,
|
|
'all_players': all_players
|
|
}
|
|
league_data.append(league_info)
|
|
print(f"DEBUG: League '{league['name']}' processed successfully", flush=True)
|
|
else:
|
|
print(f"DEBUG: Skipping league '{league['name']}' - missing data", flush=True)
|
|
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to process league '{league['name']}': {str(e)}", flush=True)
|
|
print(f"ERROR: League processing traceback: {traceback.format_exc()}", flush=True)
|
|
|
|
# Debug output before rendering template
|
|
print(f"DEBUG: About to render template with {len(league_data)} leagues", flush=True)
|
|
for league_info in league_data:
|
|
print(f"DEBUG: League '{league_info['league']['name']}' has {len(league_info['all_players'])} players", flush=True)
|
|
|
|
total_game_count = sum(len(games) for games in schedule.values())
|
|
print(f"DEBUG: Schedule has {total_game_count} total games", flush=True)
|
|
|
|
try:
|
|
# Render dashboard with all collected data
|
|
result = render_template('dashboard.html',
|
|
user=user,
|
|
week=week,
|
|
league_data=league_data,
|
|
schedule=schedule,
|
|
nfl_state=nfl_state)
|
|
print(f"DEBUG: Template rendered successfully", flush=True)
|
|
return result
|
|
except Exception as e:
|
|
print(f"ERROR: Template rendering failed: {str(e)}", flush=True)
|
|
print(f"ERROR: Template rendering traceback: {traceback.format_exc()}", flush=True)
|
|
return render_template('error.html', message=f"Template error: {str(e)}")
|
|
|
|
except Exception as e:
|
|
print(f"ERROR: Dashboard function exception: {str(e)}", flush=True)
|
|
print(f"ERROR: Full dashboard traceback: {traceback.format_exc()}", flush=True)
|
|
return render_template('error.html',
|
|
message=f"Error loading data: {str(e)}")
|
|
|
|
@app.route('/api/refresh/<username>/<int:week>')
|
|
def refresh_data(username, week):
|
|
"""API endpoint for live score updates"""
|
|
print(f"DEBUG: Refresh data API - username: '{username}', week: {week}", flush=True)
|
|
try:
|
|
# Get user and current season
|
|
user = sleeper_api.get_user(username)
|
|
if not user:
|
|
return jsonify({'error': 'User not found'}), 404
|
|
|
|
nfl_state = sleeper_api.get_nfl_state()
|
|
season = nfl_state.get('season', str(datetime.now().year))
|
|
leagues = sleeper_api.get_user_leagues(user['user_id'], season)
|
|
league_scores = []
|
|
|
|
# Get updated scores for each league
|
|
for league in leagues:
|
|
matchups = sleeper_api.get_matchups(league['league_id'], week)
|
|
rosters = sleeper_api.get_rosters(league['league_id'])
|
|
user_roster = next((r for r in rosters if r['owner_id'] == user['user_id']), None)
|
|
|
|
if user_roster and matchups:
|
|
# Find user and opponent matchups
|
|
user_matchup = next((m for m in matchups if m['roster_id'] == user_roster['roster_id']), None)
|
|
opponent_matchup = None
|
|
if user_matchup:
|
|
opponent_matchup = next((m for m in matchups if m['matchup_id'] == user_matchup['matchup_id'] and m['roster_id'] != user_roster['roster_id']), None)
|
|
|
|
# Return current points
|
|
league_scores.append({
|
|
'league_id': league['league_id'],
|
|
'league_name': league['name'],
|
|
'user_points': user_matchup['points'] if user_matchup else 0,
|
|
'opponent_points': opponent_matchup['points'] if opponent_matchup else 0
|
|
})
|
|
|
|
return jsonify({'league_scores': league_scores})
|
|
|
|
except Exception as e:
|
|
print(f"ERROR: Refresh data exception: {str(e)}", flush=True)
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
if __name__ == '__main__':
|
|
print("DEBUG: Starting Flask app on 0.0.0.0:5000", flush=True)
|
|
print(f"DEBUG: FantasyCron {app.config['VERSION']} ready!", flush=True)
|
|
app.run(host='0.0.0.0', port=5000, debug=True)
|