Files
scoreboard/modes/fantasy.py
T
2026-08-02 05:30:23 -04:00

182 lines
6.2 KiB
Python

import requests
from PIL import Image
from time import time
from rgbmatrix import graphics
from vars import PANEL_HEIGHT, PANEL_WIDTH, GAME_WIDTH, DIVIDER_COLOR, Colors, font, font_small
players = {
"team1": [],
"team2": []
}
last_fetch = 0
scroll_x = 0
scroll_speed = 10
frames_per_tick = 2
tick = 0
times_scrolled = 0
virtual_canvas = None
virtual_dirty = True
def rbg(color_tuple):
r, g, b = color_tuple
return graphics.Color(r, b, g)
def fetch_data():
try:
resp = requests.get("https://api.alexav.gg/v4/sports/fantasy", timeout=5)
resp.raise_for_status()
data = resp.json()
for player in data["team1"]["players"]:
print(player)
players['team1'].append({
"first_name": player['first_name'],
"last_name": player['last_name'],
"abbr_name": f"{player['first_name'][0]}. {player['last_name']}",
"position": player['position'],
"team": player['team'],
"injury_status": player.get('injury_status'),
"injury_body_part": player.get('injury_body_part')
})
for player in data["team2"]["players"]:
print(player)
players['team1'].append({
"first_name": player['first_name'],
"last_name": player['last_name'],
"abbr_name": f"{player['first_name'][0]}. {player['last_name']}",
"position": player['position'],
"team": player['team'],
"injury_status": player.get('injury_status'),
"injury_body_part": player.get('injury_body_part')
})
return players
except Exception as e:
print(f"[fantasy] fetch error: {e}")
return None
def draw_text_overlay(canvas, players, scroll_x):
total_width = GAME_WIDTH * len(players)
for i, player in enumerate(players):
base_x = (i * GAME_WIDTH) - scroll_x
# draw twice to handle the wrap-around copy
for wrap in [0, total_width]:
x = base_x + wrap
# cull slots fully off screen
if x + GAME_WIDTH < 0 or x >= PANEL_WIDTH:
continue
graphics.DrawText(canvas, font_small, x + 18, 11,
rbg(Colors.WHITE.value), player['abbr_name'])
graphics.DrawText(canvas, font_small, x + 18, 27,
rbg(Colors.WHITE.value), player['team'])
# graphics.DrawText(canvas, font, x + 40, 13,
# rbg(Colors.WHITE.value), str(game["away_score"]))
# graphics.DrawText(canvas, font, x + 40, 29,
# rbg(Colors.WHITE.value), str(game["home_score"]))
# # if the time is shown it should be split between lines
# # if not, just display the status
# if "AM" in game["status"] or "PM" in game["status"]:
# game_status_split = game["status"].split("-")
# date = game_status_split[0].strip()
# time = game_status_split[1].strip()
# graphics.DrawText(canvas, font_small, x + 60, 10,
# rbg(Colors.YELLOW.value), date)
# graphics.DrawText(canvas, font_small, x + 60, 20,
# rbg(Colors.YELLOW.value), time)
# graphics.DrawText(canvas, font_small, x + 60, 30,
# rbg(Colors.YELLOW.value), game["venue"])
# else:
# graphics.DrawText(canvas, font_small, x + 65, 20,
# rbg(Colors.YELLOW.value), game["status"])
def render_player(matrix, img, player, x_offset):
league = "nfl"
away_logo = matrix.load_logo(league, player['team'])
home_logo = matrix.load_logo(league, player['team'])
if away_logo:
img.paste(away_logo.resize((14, 14)), (x_offset, 0))
if home_logo:
img.paste(home_logo.resize((14, 14)), (x_offset, 16))
# divider on right edge (except last slot handled by wrapping)
for row in range(PANEL_HEIGHT):
img.putpixel((x_offset + GAME_WIDTH - 1, row), DIVIDER_COLOR)
def build_canvas(matrix, team):
print(players)
total_players = len(players[team])
total_width = GAME_WIDTH * (total_players + 4)
img = Image.new("RGB", (total_width, PANEL_HEIGHT), (0,0,0))
for i, player in enumerate(players[team] * 2):
if i >= total_players + 4:
break
render_player(matrix, img, player, i * GAME_WIDTH)
return img, total_players
def blit_slice(canvas, pil_img, x_offset):
total_width = pil_img.width
for x in range(PANEL_WIDTH):
src_x = (x_offset + x) % total_width
for y in range(PANEL_HEIGHT):
r, g, b = pil_img.getpixel((src_x, y))
canvas.SetPixel(x, y, r, b, g)
def draw_frame(matrix):
global players, last_fetch, virtual_canvas, virtual_dirty, scroll_x, tick
global total_players
current_team = "team1"
now = time()
if now - last_fetch > 30 or not players['team1'] or not players['team2']:
players = fetch_data()
last_fetch = now
virtual_dirty = True
if virtual_dirty or virtual_canvas is None:
result = build_canvas(matrix, current_team)
if result:
virtual_canvas, total_players = result
virtual_dirty = False
scroll_x = 0
matrix.canvas.Clear()
if not len(players[current_team]) > 0:
graphics.DrawText(matrix.canvas, font, 10, 22,
rbg(Colors.RED.value),
"No players found")
scroll_x = tick = 0
return matrix.canvas
total_scroll_width = GAME_WIDTH * len(players[current_team])
if virtual_canvas:
blit_slice(matrix.canvas, virtual_canvas, scroll_x)
draw_text_overlay(matrix.canvas, players[current_team], scroll_x)
tick += 1
if tick >= frames_per_tick:
tick = 0
next_x = scroll_x + scroll_speed
if next_x >= total_scroll_width:
scroll_x = 0
tick = 0
if current_team == "team1":
current_team = "team2"
return matrix.canvas
else:
current_team = "team1"
return None
scroll_x = next_x
return matrix.canvas