Skip to content

Commit 0bf93a2

Browse files
authored
Merge pull request #35 from TheFinalJoke/sportmatrix
Started the offseason
2 parents 9eeac73 + 34ce9c1 commit 0bf93a2

File tree

8 files changed

+346
-62
lines changed

8 files changed

+346
-62
lines changed

lib/deprecated_install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ echo "It Could take 10-20 Mins"
1212
echo "On RASPBERRY PI ZERO It Could take longer than 20 mins"
1313
echo "Installing Build Essentials"
1414
sleep 5
15-
apt install -y build-essential git libssl-dev libffi-dev python3-openssl python-dev python3-setuptools python3-pip python3-dev python3-pillow python3-numpy python3-gpiozero python3-cairosvg libatlas3-base libatlas-base-dev libraqm-dev jq pastebinit neofetch zsh dbus libjpeg-dev zlib1g-dev
15+
apt install -y build-essential git libssl-dev libffi-dev python3-openssl python-dev python3-setuptools python3-pip python3-dev python3-pillow python3-numpy python3-gpiozero python3-cairosvg libatlas3-base libatlas-base-dev libraqm-dev jq pastebinit neofetch zsh dbus libjpeg-dev zlib1g-dev libxml2-dev libxslt-dev python-dev libbz2-dev liblzma-dev
1616
cd /usr/local/bin/
1717
if [ ! -f /usr/local/bin/Python-3.8.9.tgz ]
1818
then

lib/sports/sports.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async def run(self):
4242
self.logger.debug('Got basketball in config')
4343
basketball = Basketball(self.token, self.config['sport'], self.headers)
4444
basketball_return = await basketball.run()
45-
sport_data['Sport'].update({'baseketball': basketball_return})
45+
sport_data['Sport'].update({'basketball': basketball_return})
4646
elif 'hockey' == self.sport.get('sport').lower():
4747
self.logger.debug('Got Hockey from Config')
4848
hockey = Hockey(self.token, self.config['sport'], self.headers)
@@ -53,6 +53,7 @@ async def run(self):
5353
class Sport(Caller):
5454
def __init__(self, api) -> None:
5555
super().__init__()
56+
self.api_type = ""
5657
self.api = api
5758
self.full_sport = self.api['Sport']
5859
self.sport = [*self.full_sport]
@@ -75,7 +76,6 @@ def __init__(self, api) -> None:
7576
self._vs = [(game.get('game_id'), (game['teams']['home']['name'], game['teams']['away']['name'])) for game in self.next_game]
7677
self._status = [(game.get('game_id'), game.get('status')) for game in self.next_game]
7778
self._game_result = {game.get('game_id'): game.get('score') for game in self.next_game}
78-
7979
def __repr__(self):
8080
attrs = [
8181
f"length={self._length}",
@@ -101,7 +101,7 @@ def build_standings(self):
101101
position = []
102102
# Can Be Empty Must try and except for that
103103
for pos in self.main_sport['standings'].get('response')[0]:
104-
if pos.get('stage') != "MLB - Regular Season":
104+
if pos.get('stage') != "MLB - Regular Season" or pos.get('stage') != "NBA - Regular Season":
105105
continue
106106
position.append({'name': pos.get('team').get('name'),
107107
'position': pos.get('position'),
@@ -183,4 +183,7 @@ def get_scores(self):
183183
return self._game_result
184184

185185
def get_specific_score(self, game_id):
186-
return self._game_result.get(game_id)
186+
return self._game_result.get(game_id)
187+
188+
class APISports(Sport):
189+
pass

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def poll_rgbmatrix(self):
7474
return rgboptions
7575

7676
async def init_matrix(self, matrix):
77-
verified_modules = [TimeMatrix(matrix)]
77+
verified_modules = [] #[TimeMatrix(matrix)]
7878
modules = self.get_modules_to_run()
7979
if 'weather' in modules:
8080
self.logger.debug("Initialized Weather")

matrix/matrix.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ def make_new_image(self, size: Tuple[int]) -> Image:
6161

6262
def add_image_to_images(self, image: Image) -> None:
6363
self.images.append(image)
64+
65+
def paste_image(self, image: Image, position: Tuple[int, int]) -> None:
66+
self.image.paste(image, position)
6467

6568
def reset_image_queue(self) -> None:
6669
self.images = deque([self.image])

matrix/sport/sportmatrix.py

Lines changed: 182 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
#!/usr/bin/env python3
22

33
import asyncio
4+
import os
45
import time
6+
import urllib.request
7+
from datetime import datetime
58
from typing import List, Dict, Tuple
69
from collections import deque
710
from datetime import datetime, timedelta
8-
from PIL import ImageFont, Image
11+
from PIL import ImageFont, Image, ImageDraw
912
from lib.sports.sports import Sport
1013
from matrix.matrix import Matrix
1114
from lib.sports.baseball.baseball import Baseball
1215
from lib.sports.basketball.basketball import Basketball
1316
from lib.sports.hockey.hockey import Hockey
14-
17+
from matrix.sport.team_mapping import BASEBALL_TEAMS, BASKETBALL_TEAMS
1518
class BaseballMatrix(Matrix):
1619
def __init__(self, matrix, api, logger) -> None:
1720
self.matrix = matrix
@@ -64,13 +67,17 @@ def baseball_divisions(self, standings: List[Dict]) -> List[str]:
6467

6568
def determine_nextgame(self, nextgame_api):
6669
now = datetime.now()
67-
last_16 = now - timedelta(hours=16)
6870
status = ("FT", "ABD")
6971
for game in nextgame_api:
70-
if last_16 <= datetime.fromtimestamp(game['timestamp']) <= now:
72+
if "IN" in game['status']:
73+
# During the game
74+
return game
75+
if game['status'] == "FT" and datetime.fromtimestamp(game['timestamp']).date() == datetime.today().date():
76+
# Same Day will display for the rest of the day
7177
return game
7278
if game['status'] not in status:
7379
return game
80+
7481
def away_team(self, nextgame_data):
7582
away = nextgame_data['teams']['away']
7683
away.update(nextgame_data['score']['away'])
@@ -79,64 +86,186 @@ def home_team(self, nextgame_data):
7986
home = nextgame_data['teams']['home']
8087
home.update(nextgame_data['score']['home'])
8188
return home
82-
def render_baseball_standings(self, api):
83-
self.clear()
84-
self.reload_image()
85-
scrolling_font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
86-
if 'baseball'in api.sport:
87-
self.logger.info("Found Baseball, Displaying Baseball Matrix")
88-
color = (156,163,173)
89-
# Can't Have multiple images and or buffers
90-
american, national = self.baseball_divisions(api.standings)
91-
american.extend(national)
92-
text = "\n".join(american)
93-
img_width, img_height = self.get_text_size(text)
94-
self.logger.info("Displaying Standings")
95-
ypos = 0
96-
while ypos < 100:
97-
ypos += 1
98-
if ypos == 1 or ypos % 8 == 0:
99-
xpos = 0
100-
pause = True
101-
while xpos < img_width:
102-
if xpos > 100:
103-
break
104-
self.reload_image()
105-
self.draw_multiline_text((-xpos, -ypos-ypos), text, font=scrolling_font, fill=color, spacing=1) if ypos > 1 else self.draw_multiline_text((-xpos, 0), text, font=scrolling_font, fill=color, spacing=1)
106-
self.render_image()
107-
time.sleep(3) if pause else time.sleep(0)
108-
xpos += 1
109-
pause = False
110-
self.reload_image()
111-
self.image_resize(64, img_height)
112-
self.draw_multiline_text((0, -ypos), text, font=scrolling_font, fill=color, spacing=1)
113-
self.render_image(yoffset=-ypos)
114-
def render_baseball_nextgame(self, api):
115-
self.clear()
116-
self.reload_image()
117-
self.draw_rectangle([(0,0), (63, 31)])
118-
self.draw_line([(32,0), (32,32)])
89+
90+
def get_logo(self, logo_url, name):
91+
file_name = f"/tmp/{name}.png"
92+
if not os.path.isfile(file_name):
93+
urllib.request.urlretrieve(logo_url, file_name)
94+
return file_name
95+
96+
def build_in_game_image(self, nextgame):
97+
middle_image = self.make_new_image((34,16))
98+
middle_draw = ImageDraw.Draw(middle_image)
11999
font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
120-
self.draw_text((28, 14), "VS", font=font)
121-
nextgame = self.determine_nextgame(api.next_game)
122-
away_data = self.away_team(nextgame_data=nextgame)
100+
status = nextgame['status']
101+
score = (nextgame['teams']['home']['total'], nextgame['teams']['away']['total'])
102+
middle_draw.multiline_text((10,0), f"{status}\n{score[0]}-{score[1]}", font=font)
103+
return middle_image, (15, 0)
104+
def build_finished_game_image(self, nextgame):
105+
middle_image = self.make_new_image((34,16))
106+
middle_draw = ImageDraw.Draw(middle_image)
107+
font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
108+
status = nextgame['status']
109+
score = (nextgame['teams']['home']['total'], nextgame['teams']['away']['total'])
110+
middle_draw.multiline_text((10,0), f"{status}\n{score[0]}-{score[1]}", font=font)
111+
return middle_image, (15, 0)
112+
113+
def check_offseason(self, api):
114+
try:
115+
start_time, end_time = api.get_timestamps[0][1], api.get_timestamps[-1][1]
116+
if datetime.fromtimestamp(start_time) <= datetime.now() <= datetime.fromtimestamp(end_time):
117+
return True
118+
except Exception:
119+
return False
120+
def build_next_game_image(self, nextgame):
121+
middle_image = self.make_new_image((34,16))
122+
middle_draw = ImageDraw.Draw(middle_image)
123+
font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
124+
time = datetime.fromtimestamp(nextgame['timestamp']).strftime("%I:%M%p %a")
125+
time = "\n ".join(time.split())
126+
middle_draw.multiline_text((0,0), f'{time}', font=font)
127+
return middle_image, (15, 0)
128+
129+
def build_home_away_image(self, nextgame):
123130
home_data = self.home_team(nextgame)
124-
self.render_image()
125-
breakpoint()
126-
131+
home_logo = Image.open(self.get_logo(home_data['logo'], home_data['id']))
132+
home_logo.thumbnail((16,16))
133+
away_data = self.away_team(nextgame)
134+
away_logo = Image.open(self.get_logo(away_data['logo'], away_data['id']))
135+
away_logo.thumbnail((16,16))
136+
return (home_logo, (-2,0)), (away_logo, (50, 0))
137+
138+
def build_middle_nextgame(self, api):
139+
nextgame = self.determine_nextgame(api.next_game)
140+
if "IN" in nextgame['status']:
141+
return self.build_in_game_image(nextgame)
142+
elif "NS" == nextgame['status']:
143+
return self.build_next_game_image(nextgame)
144+
elif "FT" == nextgame['status']:
145+
return self.build_finished_game_image(nextgame)
146+
147+
def build_middle_image(self, api):
148+
nextgame = self.determine_nextgame(api.next_game)
149+
home_image, away_image = self.build_home_away_image(nextgame)
150+
middle_image = self.build_middle_nextgame(api)
151+
master_middle_image = self.make_new_image((64, 16))
152+
master_middle_image.paste(home_image[0], home_image[1])
153+
master_middle_image.paste(away_image[0], away_image[1])
154+
master_middle_image.paste(middle_image[0], middle_image[1])
155+
return master_middle_image, (0,9)
156+
157+
def build_top_home_away_images(self, nextgame, xpos):
158+
font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
159+
top_home_image = self.make_new_image((22,8))
160+
top_home_draw = ImageDraw.Draw(top_home_image)
161+
top_away_image = self.make_new_image((22,8))
162+
top_away_draw = ImageDraw.Draw(top_away_image)
163+
hometeam = nextgame['teams']['home']['name']
164+
awayteam = nextgame['teams']['away']['name']
165+
top_home_draw.text((-xpos,0), hometeam, font=font)
166+
top_away_draw.text((-xpos,0), awayteam, font=font)
167+
return top_home_image, top_away_image
168+
169+
def build_top_image(self, api, xpos):
170+
nextgame = self.determine_nextgame(api.next_game)
171+
master_top_image = self.make_new_image((64, 8))
172+
home_image, away_image = self.build_top_home_away_images(nextgame, xpos)
173+
top_middle_image = self.make_new_image((22,8))
174+
top_middle_draw = ImageDraw.Draw(top_middle_image)
175+
top_middle_draw.text((5,0), "VS", font=ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8))
176+
master_top_image.paste(home_image, (0,0))
177+
master_top_image.paste(away_image, (44,0))
178+
master_top_image.paste(top_middle_image, (22,0))
179+
return master_top_image, (0,0)
180+
181+
def build_standings_image(self, api, xpos) -> Tuple[int, int]:
182+
""",
183+
This is most bottom Image
184+
"""
185+
standings_image = Image.new("RGB", (64,8))
186+
standings_draw = ImageDraw.Draw(standings_image)
187+
scrolling_font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
188+
color = (156,163,173)
189+
# Can't Have multiple images and or buffers
190+
american, national = self.baseball_divisions(api.standings)
191+
american.extend(national)
192+
text = " ".join(american)
193+
img_width, img_height = self.get_text_size(text)
194+
standings_draw.text(
195+
(-xpos, 0),
196+
text,
197+
font=scrolling_font,
198+
fill=color
199+
)
200+
return standings_image, (0, 25)
201+
127202
def render(self, api):
128203
self.clear()
129204
self.reload_image()
130-
scrolling_font = ImageFont.truetype("/usr/share/fonts/fonts/04B_03B_.TTF", 8)
131205
if 'baseball'in api.sport:
132206
# Check Data if Offseason if yes Diplay Offseason, Otherwise Display Data
133207
# Check data if Game is active, if yes Display game -> Score Inning AT bat Maybe?
134208
# Else Display next game
135209
# Only do standings right now
136-
self.render_baseball_standings(api)
137-
# self.render_baseball_nextgame(api)
210+
self.logger.info("Found Baseball, Displaying Baseball Matrix")
211+
if self.check_offseason(api):
212+
xpos = 0
213+
xpos_for_top = 0
214+
while xpos < 2700:
215+
self.reload_image()
216+
images = (
217+
self.build_standings_image(api, xpos),
218+
self.build_middle_image(api),
219+
self.build_top_image(api, xpos_for_top),
220+
)
221+
for image, position in images:
222+
self.paste_image(image, position)
223+
self.render_image()
224+
xpos +=1
225+
xpos_for_top += 1
226+
if xpos_for_top == 100:
227+
xpos_for_top = 0
228+
time.sleep(3) if xpos == 1 else time.sleep(.05)
229+
else:
230+
font = ImageFont.truetype("/usr/share/fonts/fonts/04b24.otf", 14)
231+
self.draw_multiline_text((0, 0), "Basketball\nOffseason", font=font)
232+
self.render_image()
233+
time.sleep(30)
138234
if 'basketball' in api.sport:
139-
sportmatrix = BasketballMatrix(self.matrix, api, self.logger)
235+
# Check Data if Offseason if yes Diplay Offseason, Otherwise Display Data
236+
# Check data if Game is active, if yes Display game -> Score Inning AT bat Maybe?
237+
# Else Display next game
238+
# Only do standings right now
239+
self.logger.info("Found Basketball, Displaying Basketball Matrix")
240+
if self.check_offseason(api):
241+
xpos = 0
242+
xpos_for_top = 0
243+
while xpos < 2700:
244+
self.reload_image()
245+
images = (
246+
self.build_standings_image(api, xpos),
247+
self.build_middle_image(api),
248+
self.build_top_image(api, xpos_for_top),
249+
)
250+
for image, position in images:
251+
self.paste_image(image, position)
252+
self.render_image()
253+
xpos +=1
254+
xpos_for_top += 1
255+
if xpos_for_top == 100:
256+
xpos_for_top = 0
257+
time.sleep(3) if xpos == 1 else time.sleep(.05)
258+
else:
259+
font = ImageFont.truetype("/usr/share/fonts/fonts/04b24.otf", 14)
260+
self.draw_multiline_text((0, 0), "Basketball\nOffseason", font=font)
261+
self.render_image()
262+
time.sleep(30)
140263
if 'hockey' in api.sport:
141-
sportmatrix = HockeyMatrix(self.matrix, api, self.logger)
142-
264+
self.logger.info("Found Hockey, Displaying Hockey Matrix")
265+
if self.check_offseason(api):
266+
sportmatrix = HockeyMatrix(self.matrix, api, self.logger)
267+
else:
268+
font = ImageFont.truetype("/usr/share/fonts/fonts/04b24.otf", 14)
269+
self.draw_multiline_text((0, 0), "Hockey\nOffseason", font=font)
270+
self.render_image()
271+
time.sleep(30)

0 commit comments

Comments
 (0)