162 lines
5 KiB
Python
162 lines
5 KiB
Python
#!/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('/input')
|
|
def input_page():
|
|
"""Mobile-friendly score input page"""
|
|
players = get_all_players()
|
|
return render_template('input.html', players=players)
|
|
|
|
@app.route('/')
|
|
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'
|
|
}
|
|
)
|
|
|
|
@app.route('/reset', methods=['GET', 'POST'])
|
|
def reset_database():
|
|
"""Reset database to initial state"""
|
|
try:
|
|
with sqlite3.connect('database.db') as conn:
|
|
# Clear existing data
|
|
conn.execute('DELETE FROM players')
|
|
|
|
# Re-initialize with default players
|
|
for i in range(1, 15):
|
|
conn.execute(
|
|
'INSERT INTO players (id, name, score) VALUES (?, ?, ?)',
|
|
(i, f'Player {i}', 0)
|
|
)
|
|
conn.commit()
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': 'Database reset successfully',
|
|
'players_created': 14
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({
|
|
'success': False,
|
|
'error': str(e)
|
|
}), 500
|
|
|
|
if __name__ == '__main__':
|
|
init_db()
|
|
app.run(host='0.0.0.0', port=8080, debug=True)
|