change how font is loaded via systemctl - added direct paths

This commit is contained in:
Chuck
2025-08-13 20:36:23 -05:00
parent 8e1b04550b
commit 6bc1039ed6
16 changed files with 132 additions and 90 deletions

View File

@@ -46,35 +46,11 @@ class CacheManager:
self.logger.warning("ConfigManager not available, using default cache intervals")
def _get_writable_cache_dir(self) -> Optional[str]:
"""Tries to find or create a writable cache directory in a few common locations."""
# Attempt 1: User's home directory (handling sudo)
"""Tries to find or create a writable cache directory, preferring a system path when available."""
# Attempt 1: System-wide persistent cache directory (preferred for services)
try:
real_user = os.environ.get('SUDO_USER') or os.environ.get('USER', 'default')
if real_user and real_user != 'root':
home_dir = os.path.expanduser(f"~{real_user}")
else:
home_dir = os.path.expanduser('~')
user_cache_dir = os.path.join(home_dir, '.ledmatrix_cache')
os.makedirs(user_cache_dir, exist_ok=True)
# Test writability
test_file = os.path.join(user_cache_dir, '.writetest')
with open(test_file, 'w') as f:
f.write('test')
os.remove(test_file)
return user_cache_dir
except Exception as e:
self.logger.warning(f"Could not use user-specific cache directory: {e}")
# Attempt 2: System-wide persistent cache directory (for sudo scenarios)
try:
# Try /var/cache/ledmatrix first (most standard)
system_cache_dir = '/var/cache/ledmatrix'
# Check if directory exists and we can write to it
if os.path.exists(system_cache_dir):
# Test if we can write to the existing directory
test_file = os.path.join(system_cache_dir, '.writetest')
try:
with open(test_file, 'w') as f:
@@ -84,13 +60,30 @@ class CacheManager:
except (IOError, OSError):
self.logger.warning(f"Directory exists but is not writable: {system_cache_dir}")
else:
# Try to create the directory
os.makedirs(system_cache_dir, exist_ok=True)
if os.access(system_cache_dir, os.W_OK):
return system_cache_dir
except Exception as e:
self.logger.warning(f"Could not use /var/cache/ledmatrix: {e}")
# Attempt 2: User's home directory (handling sudo), but avoid /root preference
try:
real_user = os.environ.get('SUDO_USER') or os.environ.get('USER', 'default')
if real_user and real_user != 'root':
home_dir = os.path.expanduser(f"~{real_user}")
else:
# When running as root and /var/cache/ledmatrix failed, still allow fallback to /root
home_dir = os.path.expanduser('~')
user_cache_dir = os.path.join(home_dir, '.ledmatrix_cache')
os.makedirs(user_cache_dir, exist_ok=True)
test_file = os.path.join(user_cache_dir, '.writetest')
with open(test_file, 'w') as f:
f.write('test')
os.remove(test_file)
return user_cache_dir
except Exception as e:
self.logger.warning(f"Could not use user-specific cache directory: {e}")
# Attempt 3: /opt/ledmatrix/cache (alternative persistent location)
try:
opt_cache_dir = '/opt/ledmatrix/cache'
@@ -240,6 +233,16 @@ class CacheManager:
pass
except Exception as e:
self.logger.error(f"Atomic write failed for key '{key}': {e}")
# Attempt one-time fallback write directly into /var/cache/ledmatrix if available
try:
fallback_dir = '/var/cache/ledmatrix'
if os.path.isdir(fallback_dir) and os.access(fallback_dir, os.W_OK):
fallback_path = os.path.join(fallback_dir, os.path.basename(cache_path))
with open(fallback_path, 'w') as tmp_file:
json.dump(data, tmp_file, indent=4, cls=DateTimeEncoder)
self.logger.warning(f"Cache wrote to fallback location: {fallback_path}")
except Exception as e2:
self.logger.error(f"Fallback cache write also failed: {e2}")
except (IOError, OSError) as e:
self.logger.error(f"Failed to save cache for key '{key}': {e}")

View File

@@ -98,9 +98,11 @@ class DisplayManager:
self.draw = ImageDraw.Draw(self.image)
logger.info(f"Image canvas created with dimensions: {self.matrix.width}x{self.matrix.height}")
# Initialize font with Press Start 2P
# Initialize font with Press Start 2P using an absolute path so services don't fall back
try:
self.font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p_path = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
self.font = ImageFont.truetype(ps2p_path, 8)
logger.info("Initial Press Start 2P font loaded successfully")
except Exception as e:
logger.error(f"Failed to load initial font: {e}")
@@ -290,12 +292,14 @@ class DisplayManager:
def _load_fonts(self):
"""Load fonts with proper error handling."""
try:
# Load Press Start 2P font
self.regular_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
# Load Press Start 2P font using absolute path to avoid fallback when run under systemd
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p_path = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
self.regular_font = ImageFont.truetype(ps2p_path, 8)
logger.info("Press Start 2P font loaded successfully")
# Use the same font for small text, just at a smaller size
self.small_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
# Use the same font for small text (currently same size; adjust size here if needed)
self.small_font = ImageFont.truetype(ps2p_path, 8)
logger.info("Press Start 2P small font loaded successfully")
# Load 5x7 BDF font for calendar events

View File

@@ -336,8 +336,10 @@ class BaseMiLBManager:
date_font = getattr(self.display_manager, 'small_font', None)
time_font = getattr(self.display_manager, 'small_font', None)
if date_font is None or time_font is None:
date_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
time_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
date_font = ImageFont.truetype(ps2p, 8)
time_font = ImageFont.truetype(ps2p, 8)
self.logger.debug(f"[MiLB] Fonts prepared successfully")
except Exception as e:
self.logger.error(f"[MiLB] Failed to prepare fonts: {e}")
@@ -403,7 +405,9 @@ class BaseMiLBManager:
away_score = str(game_data['away_score'])
home_score = str(game_data['home_score'])
score_text = f"{away_score}-{home_score}"
score_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 12)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
score_font = ImageFont.truetype(ps2p, 12)
# Calculate position for the score text
score_width = draw.textlength(score_text, font=score_font)
@@ -415,7 +419,10 @@ class BaseMiLBManager:
# Draw records for upcoming and recent games
if self.show_records and game_data['status'] in ['status_scheduled', 'status_final', 'final', 'completed']:
try:
record_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
# Resolve 4x6 font via absolute path
script_dir = os.path.dirname(os.path.abspath(__file__))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
record_font = ImageFont.truetype(font_4x6, 6)
except IOError:
record_font = ImageFont.load_default()

View File

@@ -264,8 +264,10 @@ class BaseMLBManager:
game_time_str = self._format_game_time(game_data['start_time'])
# Draw date and time using NHL-style fonts
date_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
time_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
date_font = ImageFont.truetype(ps2p, 8)
time_font = ImageFont.truetype(ps2p, 8)
# Draw date in center
date_width = draw.textlength(game_date, font=date_font)
@@ -302,7 +304,7 @@ class BaseMLBManager:
away_score = str(game_data['away_score'])
home_score = str(game_data['home_score'])
display_text = f"{away_score}-{home_score}"
font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 12)
font = ImageFont.truetype(ps2p, 12)
display_width = draw.textlength(display_text, font=font)
display_x = (width - display_width) // 2
display_y = (height - font.size) // 2
@@ -330,7 +332,7 @@ class BaseMLBManager:
away_score = str(game_data['away_score'])
home_score = str(game_data['home_score'])
score_text = f"{away_score}-{home_score}"
score_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 12)
score_font = ImageFont.truetype(ps2p, 12)
# Calculate position for the score text
score_width = draw.textlength(score_text, font=score_font)

View File

@@ -193,11 +193,14 @@ class BaseNBAManager:
"""Load fonts used by the scoreboard."""
fonts = {}
try:
# Try to load the Press Start 2P font first
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10)
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
# Try to load the Press Start 2P font first using absolute paths
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 10)
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(ps2p, 8)
fonts['status'] = ImageFont.truetype(font_4x6, 6)
logging.info("[NBA] Successfully loaded Press Start 2P font for all text elements")
except IOError:
logging.warning("[NBA] Press Start 2P font not found, trying 4x6 font.")

View File

@@ -240,7 +240,9 @@ class BaseNCAABaseballManager:
status_x = (width - status_width) // 2
status_y = 2
self.display_manager.draw = draw
status_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Using a default small font
script_dir = os.path.dirname(os.path.abspath(__file__))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
status_font = ImageFont.truetype(font_4x6, 6) # Using a default small font
self._draw_text_with_outline(draw, status_text, (status_x, status_y), status_font)
game_time = datetime.fromisoformat(game_data['start_time'].replace('Z', '+00:00'))
@@ -263,8 +265,9 @@ class BaseNCAABaseballManager:
game_time_str = self._format_game_time(game_data['start_time'])
date_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
time_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
date_font = ImageFont.truetype(ps2p, 8)
time_font = ImageFont.truetype(ps2p, 8)
date_width = draw.textlength(game_date, font=date_font)
date_x = (width - date_width) // 2
@@ -279,7 +282,7 @@ class BaseNCAABaseballManager:
# For recent/final games, show scores and status
elif game_data['status'] in ['status_final', 'final', 'completed']:
status_text = "Final"
status_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Using a default small font
status_font = ImageFont.truetype(font_4x6, 6) # Using a default small font
status_width = draw.textlength(status_text, font=status_font)
status_x = (width - status_width) // 2
status_y = 2
@@ -289,7 +292,7 @@ class BaseNCAABaseballManager:
away_score = str(game_data['away_score'])
home_score = str(game_data['home_score'])
score_text = f"{away_score}-{home_score}"
score_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 12)
score_font = ImageFont.truetype(ps2p, 12)
score_width = draw.textlength(score_text, font=score_font)
score_x = (width - score_width) // 2
@@ -298,7 +301,7 @@ class BaseNCAABaseballManager:
if self.show_records and game_data['status'] in ['status_scheduled', 'status_final', 'final', 'completed']:
try:
record_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
record_font = ImageFont.truetype(font_4x6, 6)
except IOError:
record_font = ImageFont.load_default()
@@ -339,7 +342,7 @@ class BaseNCAABaseballManager:
# Define colors for odds text
# Use a small readable font for odds; fall back to default if not available
try:
odds_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
odds_font = ImageFont.truetype(font_4x6, 6)
except IOError:
odds_font = ImageFont.load_default()
odds_color = (255, 0, 0) # Red text

View File

@@ -211,11 +211,14 @@ class BaseNCAAFBManager: # Renamed class
"""Load fonts used by the scoreboard."""
fonts = {}
try:
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10)
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Using 4x6 for status
fonts['detail'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Added detail font
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 10)
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(ps2p, 8)
fonts['status'] = ImageFont.truetype(font_4x6, 6) # Using 4x6 for status
fonts['detail'] = ImageFont.truetype(font_4x6, 6) # Added detail font
logging.info("[NCAAFB] Successfully loaded fonts") # Changed log prefix
except IOError:
logging.warning("[NCAAFB] Fonts not found, using default PIL font.") # Changed log prefix

View File

@@ -213,11 +213,13 @@ class BaseNCAAMBasketballManager:
"""Load fonts used by the scoreboard."""
fonts = {}
try:
# Try to load the Press Start 2P font first
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10)
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 10)
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(ps2p, 8)
fonts['status'] = ImageFont.truetype(font_4x6, 6)
logging.info("[NCAAMBasketball] Successfully loaded Press Start 2P font for all text elements")
except IOError:
logging.warning("[NCAAMBasketball] Press Start 2P font not found, trying 4x6 font.")

View File

@@ -182,11 +182,14 @@ class BaseNFLManager: # Renamed class
"""Load fonts used by the scoreboard."""
fonts = {}
try:
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10)
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Using 4x6 for status
fonts['detail'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Added detail font
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 10)
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(ps2p, 8)
fonts['status'] = ImageFont.truetype(font_4x6, 6) # Using 4x6 for status
fonts['detail'] = ImageFont.truetype(font_4x6, 6) # Added detail font
logging.info("[NFL] Successfully loaded fonts")
except IOError:
logging.warning("[NFL] Fonts not found, using default PIL font.")

View File

@@ -162,11 +162,13 @@ class BaseNHLManager:
"""Load fonts used by the scoreboard."""
fonts = {}
try:
# Try to load the Press Start 2P font first
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 12)
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 12)
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(ps2p, 8)
fonts['status'] = ImageFont.truetype(font_4x6, 6)
logging.info("[NHL] Successfully loaded Press Start 2P font for all text elements")
except IOError:
logging.warning("[NHL] Press Start 2P font not found, trying 4x6 font.")

View File

@@ -185,10 +185,12 @@ class OddsTickerManager:
def _load_fonts(self) -> Dict[str, ImageFont.FreeTypeFont]:
"""Load fonts for the ticker display."""
try:
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
return {
'small': ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 6),
'medium': ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8),
'large': ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10)
'small': ImageFont.truetype(ps2p, 6),
'medium': ImageFont.truetype(ps2p, 8),
'large': ImageFont.truetype(ps2p, 10)
}
except Exception as e:
logger.error(f"Error loading fonts: {e}")

View File

@@ -312,10 +312,13 @@ class BaseSoccerManager:
"""Load fonts used by the scoreboard."""
fonts = {}
try:
fonts['score'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 10) # Slightly larger score
fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
fonts['team'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Keep team abbr small
fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) # Keep status small
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
fonts['score'] = ImageFont.truetype(ps2p, 10) # Slightly larger score
fonts['time'] = ImageFont.truetype(ps2p, 8)
fonts['team'] = ImageFont.truetype(font_4x6, 6) # Keep team abbr small
fonts['status'] = ImageFont.truetype(font_4x6, 6) # Keep status small
logging.info("[Soccer] Successfully loaded custom fonts")
except IOError:
logging.warning("[Soccer] Custom fonts not found, using default PIL font.")
@@ -410,7 +413,8 @@ class BaseSoccerManager:
draw = ImageDraw.Draw(logo)
# Optionally add text to placeholder
try:
placeholder_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 12)
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
placeholder_font = ImageFont.truetype(font_4x6, 12)
text_width = draw.textlength(team_abbrev, font=placeholder_font)
text_x = (36 - text_width) // 2
text_y = 10

View File

@@ -428,7 +428,10 @@ class StockManager:
fallback = Image.new('RGBA', (32, 32), (0, 0, 0, 0))
draw = ImageDraw.Draw(fallback)
try:
font = ImageFont.truetype("assets/fonts/OpenSans-Regular.ttf", 16)
# Resolve font path absolutely to avoid fallback under systemd
script_dir = os.path.dirname(os.path.abspath(__file__))
font_path = os.path.abspath(os.path.join(script_dir, "../assets/fonts/OpenSans-Regular.ttf"))
font = ImageFont.truetype(font_path, 16)
except:
font = ImageFont.load_default()

View File

@@ -96,12 +96,10 @@ class TextDisplay:
def _load_font(self):
"""Load the specified font file (TTF or BDF)."""
font_path = self.font_path
if not os.path.isabs(font_path) and not font_path.startswith('assets/'):
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
font_path = os.path.join(base_path, font_path)
elif not os.path.isabs(font_path) and font_path.startswith('assets/'):
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
font_path = os.path.join(base_path, font_path)
# Resolve relative paths against project root based on this file location
if not os.path.isabs(font_path):
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
font_path = os.path.join(base_path, font_path)
logger.info(f"Attempting to load font: {font_path} at size {self.font_size}")

View File

@@ -337,7 +337,8 @@ class WeatherManager:
# --- Right Side (Below Condition): Current Temp ---
temp = round(weather_data['main']['temp'])
temp_text = f"{temp}°"
temp_font = self.display_manager.small_font # Using small font
# Ensure we use the intended PS2P font managed by DisplayManager
temp_font = getattr(self.display_manager, 'regular_font', self.display_manager.small_font)
temp_text_width = draw.textlength(temp_text, font=temp_font)
temp_x = self.display_manager.matrix.width - temp_text_width - 1 # Align right
temp_y = condition_y + 8 # Position below condition text (adjust 8 based on font size)

View File

@@ -38,7 +38,9 @@ class YouTubeDisplay:
def _initialize_display(self):
"""Initialize display components."""
self.font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
script_dir = os.path.dirname(os.path.abspath(__file__))
ps2p = os.path.abspath(os.path.join(script_dir, "../assets/fonts/PressStart2P-Regular.ttf"))
self.font = ImageFont.truetype(ps2p, 8)
try:
self.youtube_logo = Image.open("assets/youtube_logo.png")
except Exception as e: