#!/usr/bin/env python3 """ Fig Fam Fantasy Plinko Score Tracker A local web app for tracking player scores with real-time updates """ import sqlite3 import json from flask import Flask, render_template, request, jsonify, Response from threading import Lock import time app = Flask(__name__) db_lock = Lock() # Database Setup def init_db(): """Initialize SQLite database with players table""" with sqlite3.connect('database.db') as conn: conn.execute(''' CREATE TABLE IF NOT EXISTS players ( id INTEGER PRIMARY KEY, name TEXT NOT NULL DEFAULT '', score INTEGER DEFAULT 0 ) ''') # Initialize 14 players if empty count = conn.execute('SELECT COUNT(*) FROM players').fetchone()[0] if count == 0: for i in range(1, 15): conn.execute( 'INSERT INTO players (id, name, score) VALUES (?, ?, ?)', (i, f'Player {i}', 0) ) conn.commit() # Database Operations def get_all_players(): """Retrieve all players sorted by ID for input page""" with sqlite3.connect('database.db') as conn: conn.row_factory = sqlite3.Row return [dict(row) for row in conn.execute( 'SELECT * FROM players ORDER BY id' ).fetchall()] def get_players_by_score(): """Retrieve all players sorted by score (highest first) for scoreboard""" with sqlite3.connect('database.db') as conn: conn.row_factory = sqlite3.Row return [dict(row) for row in conn.execute( 'SELECT * FROM players ORDER BY score DESC, name ASC' ).fetchall()] def update_player(player_id, name=None, score=None): """Update player name and/or score""" with db_lock: with sqlite3.connect('database.db') as conn: if name is not None and score is not None: conn.execute( 'UPDATE players SET name = ?, score = ? WHERE id = ?', (name, score, player_id) ) elif name is not None: conn.execute( 'UPDATE players SET name = ? WHERE id = ?', (name, player_id) ) elif score is not None: conn.execute( 'UPDATE players SET score = ? WHERE id = ?', (score, player_id) ) conn.commit() # Web Routes @app.route('/') def input_page(): """Mobile-friendly score input page""" players = get_all_players() return render_template('input.html', players=players) @app.route('/scoreboard') def scoreboard(): """TV display scoreboard page""" players = get_players_by_score() # Sort by score for display return render_template('scoreboard.html', players=players) @app.route('/api/players') def api_get_players(): """API endpoint to get all players (sorted by ID for input)""" return jsonify(get_all_players()) @app.route('/api/update', methods=['POST']) def api_update_player(): """API endpoint to update player data""" data = request.get_json() player_id = data.get('id') name = data.get('name') score = data.get('score') if player_id and (name is not None or score is not None): update_player(player_id, name, score) return jsonify({'success': True}) return jsonify({'success': False, 'error': 'Invalid data'}) @app.route('/events') def events(): """Server-Sent Events for real-time scoreboard updates""" def event_stream(): last_data = None while True: players = get_players_by_score() # Sort by score for real-time updates current_data = json.dumps(players) # Send update only if data changed if current_data != last_data: yield f"data: {current_data}\n\n" last_data = current_data time.sleep(1) # Check every second return Response( event_stream(), mimetype='text/plain', headers={ 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' } ) if __name__ == '__main__': init_db() app.run(host='0.0.0.0', port=8080, debug=True)