From 6bc1039ed660819d42f7813cebbae5af5983a968 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Wed, 13 Aug 2025 20:36:23 -0500 Subject: [PATCH] change how font is loaded via systemctl - added direct paths --- src/cache_manager.py | 57 +++++++++++++++++--------------- src/display_manager.py | 16 +++++---- src/milb_manager.py | 15 ++++++--- src/mlb_manager.py | 10 +++--- src/nba_managers.py | 13 +++++--- src/ncaa_baseball_managers.py | 17 ++++++---- src/ncaa_fb_managers.py | 13 +++++--- src/ncaam_basketball_managers.py | 12 ++++--- src/nfl_managers.py | 13 +++++--- src/nhl_managers.py | 12 ++++--- src/odds_ticker_manager.py | 8 +++-- src/soccer_managers.py | 14 +++++--- src/stock_manager.py | 5 ++- src/text_display.py | 10 +++--- src/weather_manager.py | 3 +- src/youtube_display.py | 4 ++- 16 files changed, 132 insertions(+), 90 deletions(-) diff --git a/src/cache_manager.py b/src/cache_manager.py index 1bdf7340..ca858263 100644 --- a/src/cache_manager.py +++ b/src/cache_manager.py @@ -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}") diff --git a/src/display_manager.py b/src/display_manager.py index 3bbbb167..09216684 100644 --- a/src/display_manager.py +++ b/src/display_manager.py @@ -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 diff --git a/src/milb_manager.py b/src/milb_manager.py index 19624a47..b7d18fb5 100644 --- a/src/milb_manager.py +++ b/src/milb_manager.py @@ -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() diff --git a/src/mlb_manager.py b/src/mlb_manager.py index c2c1a11b..4ff0b323 100644 --- a/src/mlb_manager.py +++ b/src/mlb_manager.py @@ -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) diff --git a/src/nba_managers.py b/src/nba_managers.py index 27c7ee23..1d53f10b 100644 --- a/src/nba_managers.py +++ b/src/nba_managers.py @@ -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.") diff --git a/src/ncaa_baseball_managers.py b/src/ncaa_baseball_managers.py index 948adc86..8d9d305b 100644 --- a/src/ncaa_baseball_managers.py +++ b/src/ncaa_baseball_managers.py @@ -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 diff --git a/src/ncaa_fb_managers.py b/src/ncaa_fb_managers.py index 6436a1a7..a3e5089d 100644 --- a/src/ncaa_fb_managers.py +++ b/src/ncaa_fb_managers.py @@ -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 diff --git a/src/ncaam_basketball_managers.py b/src/ncaam_basketball_managers.py index 3983a0f4..8a379009 100644 --- a/src/ncaam_basketball_managers.py +++ b/src/ncaam_basketball_managers.py @@ -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.") diff --git a/src/nfl_managers.py b/src/nfl_managers.py index 186d4137..63d68cc8 100644 --- a/src/nfl_managers.py +++ b/src/nfl_managers.py @@ -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.") diff --git a/src/nhl_managers.py b/src/nhl_managers.py index 32723fef..5be5ff33 100644 --- a/src/nhl_managers.py +++ b/src/nhl_managers.py @@ -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.") diff --git a/src/odds_ticker_manager.py b/src/odds_ticker_manager.py index e1a323c6..ea366cc5 100644 --- a/src/odds_ticker_manager.py +++ b/src/odds_ticker_manager.py @@ -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}") diff --git a/src/soccer_managers.py b/src/soccer_managers.py index c3d1d73f..b2ad4d4e 100644 --- a/src/soccer_managers.py +++ b/src/soccer_managers.py @@ -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 diff --git a/src/stock_manager.py b/src/stock_manager.py index e0d0dd18..47e07ae3 100644 --- a/src/stock_manager.py +++ b/src/stock_manager.py @@ -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() diff --git a/src/text_display.py b/src/text_display.py index 3b094793..4ff9d56b 100644 --- a/src/text_display.py +++ b/src/text_display.py @@ -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}") diff --git a/src/weather_manager.py b/src/weather_manager.py index 3ec95fbd..4b7d9095 100644 --- a/src/weather_manager.py +++ b/src/weather_manager.py @@ -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) diff --git a/src/youtube_display.py b/src/youtube_display.py index d827c970..54884e87 100644 --- a/src/youtube_display.py +++ b/src/youtube_display.py @@ -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: