From 01c0e3f69bb8e4c06f328ad56170cdd3f2d35ac9 Mon Sep 17 00:00:00 2001 From: Chuck Date: Thu, 2 Apr 2026 09:01:21 -0400 Subject: [PATCH 1/3] fix(masters): paginate course overview across all 18 holes render_course_overview only split holes into 2 pages (front/back nine) and broke early when holes didn't fit on screen, silently dropping holes 4-9 and 13-18. Now calculates how many holes fit and paginates across all 18 holes, matching the pattern used by render_past_champions and render_leaderboard. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../masters_renderer_enhanced.py | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/plugins/masters-tournament/masters_renderer_enhanced.py b/plugins/masters-tournament/masters_renderer_enhanced.py index 4451899..b83f245 100644 --- a/plugins/masters-tournament/masters_renderer_enhanced.py +++ b/plugins/masters-tournament/masters_renderer_enhanced.py @@ -328,16 +328,32 @@ def render_live_alert( return img def render_course_overview(self, page: int = 0) -> Optional[Image.Image]: - """Render Augusta National overview - paginated front/back nine.""" + """Render Augusta National overview - paginated across all 18 holes.""" img = self._draw_gradient_bg(COLORS["masters_dark"], COLORS["masters_green"]) draw = ImageDraw.Draw(img) - if page % 2 == 0: - title = "FRONT NINE" - holes = range(1, 10) + font = self.font_detail + + # Calculate how many holes fit on screen + content_top = self.header_height + 3 + content_bottom = self.height - self.footer_height - 4 + usable_h = content_bottom - content_top + line_h = self._text_height(draw, "A", font) + 3 + max_holes = max(1, usable_h // line_h) + + # Paginate across all 18 holes + all_holes = list(range(1, 19)) + total_pages = max(1, (len(all_holes) + max_holes - 1) // max_holes) + page = page % total_pages + + start = page * max_holes + holes = all_holes[start : start + max_holes] + + # Title based on which nine we're showing + if holes[0] <= 9: + title = "FRONT NINE" if holes[-1] <= 9 else "FRONT/BACK" else: title = "BACK NINE" - holes = range(10, 19) self._draw_header_bar(img, draw, title, show_logo=True) @@ -347,35 +363,25 @@ def render_course_overview(self, page: int = 0) -> Optional[Image.Image]: draw.text((2, y), f"Par {par}", fill=COLORS["white"], font=self.font_body) return img - y = self.header_height + 3 - font = self.font_detail - line_h = self._text_height(draw, "A", font) + 3 - - # Show each hole with spacing + y = content_top for h in holes: info = AUGUSTA_HOLES[h] - # Hole number in yellow num_text = f"{h:2d}" draw.text((3, y), num_text, fill=COLORS["masters_yellow"], font=font) - # Hole name name = info["name"] if self.tier == "small": name = name[:10] draw.text((18, y), name, fill=COLORS["white"], font=font) - # Par and yardage right-aligned par_text = f"P{info['par']} {info['yardage']}y" pw = self._text_width(draw, par_text, font) draw.text((self.width - pw - 3, y), par_text, fill=COLORS["light_gray"], font=font) y += line_h - if y > self.height - self.footer_height - 4: - break - # Page dots (2 pages: front/back) - self._draw_page_dots(draw, page % 2, 2) + self._draw_page_dots(draw, page, total_pages) return img From 35a5f32658127fb2ccda7c22868068b43e5bfaa3 Mon Sep 17 00:00:00 2001 From: Chuck Date: Thu, 2 Apr 2026 09:50:14 -0400 Subject: [PATCH 2/3] fix(masters): enlarge countdown logo and show days + hours - Compact layout logo increased from 48x20 max to 56x28 max, and positioned to use available space better - Large layout logo reduced from 55% to 45% width to give more room for the countdown text - Countdown now shows "8d 14h" instead of just "8" when days > 0, and "HOURS TO GO" instead of "HOURS" for sub-day countdowns - Text positioned dynamically below logo instead of at fixed mid_y Co-Authored-By: Claude Opus 4.6 (1M context) --- .../masters-tournament/masters_renderer.py | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/plugins/masters-tournament/masters_renderer.py b/plugins/masters-tournament/masters_renderer.py index 6899412..872e724 100644 --- a/plugins/masters-tournament/masters_renderer.py +++ b/plugins/masters-tournament/masters_renderer.py @@ -825,13 +825,13 @@ def render_countdown(self, days: int, hours: int, minutes: int) -> Optional[Imag img = self._draw_gradient_bg(COLORS["masters_dark"], COLORS["masters_green"]) draw = ImageDraw.Draw(img) - # Countdown text + # Countdown text — show days + hours for context, or hours:minutes when < 1 day if days > 0: - count_text = str(days) - unit_text = "DAYS" if days > 1 else "DAY" + count_text = f"{days}d {hours}h" + unit_text = "UNTIL THE MASTERS" elif hours > 0: count_text = f"{hours}:{minutes:02d}" - unit_text = "HOURS" + unit_text = "HOURS TO GO" else: count_text = "NOW" unit_text = "" @@ -840,18 +840,18 @@ def render_countdown(self, days: int, hours: int, minutes: int) -> Optional[Imag min_right_width = 40 if self.tier == "large": logo = self.logo_loader.get_masters_logo( - max_width=int(self.width * 0.55), - max_height=self.height - 6, + max_width=int(self.width * 0.45), + max_height=self.height - 4, ) if logo and (self.width - logo.width - 12) >= min_right_width: - lx = 4 + lx = 3 ly = (self.height - logo.height) // 2 self._draw_logo_with_glow(img, logo, lx, ly) right_x = lx + logo.width + 6 right_w = self.width - right_x - 2 right_cx = right_x + right_w // 2 - until_text = "UNTIL THE MASTERS" + until_text = unit_text utw = self._text_width(draw, until_text, self.font_detail) if utw > right_w: until_text = "TO MASTERS" @@ -874,30 +874,39 @@ def render_countdown(self, days: int, hours: int, minutes: int) -> Optional[Imag unit_text, fill=COLORS["light_gray"], font=self.font_detail) return img - # Compact layout: logo centered at top, countdown below + # Compact layout: logo centered at top (larger), countdown below logo = self.logo_loader.get_masters_logo( - max_width=min(self.width - 10, 48), - max_height=min(self.height // 3, 20), + max_width=min(self.width - 6, 56), + max_height=min(int(self.height * 0.45), 28), ) + logo_bottom = 3 if logo: lx = (self.width - logo.width) // 2 - self._draw_logo_with_glow(img, logo, lx, 3) + self._draw_logo_with_glow(img, logo, lx, 2) + logo_bottom = 2 + logo.height + 2 + + # Position text below logo + remaining = self.height - logo_bottom + detail_h = self._text_height(draw, "A", self.font_detail) + count_h = self._text_height(draw, count_text, self.font_score) + + if self.tier == "tiny": + until_text = "TO MASTERS" + else: + until_text = unit_text + + # Center the text block in remaining space + text_block_h = detail_h + 2 + count_h + text_y = logo_bottom + max(0, (remaining - text_block_h) // 2) - mid_y = self.height // 2 - until_text = "TO MASTERS" if self.tier == "tiny" else "UNTIL THE MASTERS" uw = self._text_width(draw, until_text, self.font_detail) - draw.text(((self.width - uw) // 2, mid_y - 6), + draw.text(((self.width - uw) // 2, text_y), until_text, fill=COLORS["white"], font=self.font_detail) cw = self._text_width(draw, count_text, self.font_score) - self._text_shadow(draw, ((self.width - cw) // 2, mid_y + 4), + self._text_shadow(draw, ((self.width - cw) // 2, text_y + detail_h + 2), count_text, self.font_score, COLORS["masters_yellow"]) - if unit_text: - uw2 = self._text_width(draw, unit_text, self.font_detail) - draw.text(((self.width - uw2) // 2, mid_y + 16), - unit_text, fill=COLORS["light_gray"], font=self.font_detail) - return img # ═══════════════════════════════════════════════════════════ From 5fb877f38dabb6366394e56f0a976d7bee88b600 Mon Sep 17 00:00:00 2001 From: Chuck Date: Thu, 2 Apr 2026 10:01:23 -0400 Subject: [PATCH 3/3] fix(masters): put countdown label below the number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show the big countdown number first (8d 14h), with "UNTIL THE MASTERS" underneath in gray — cleaner than repeating the label above and below. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../masters-tournament/masters_renderer.py | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/plugins/masters-tournament/masters_renderer.py b/plugins/masters-tournament/masters_renderer.py index 872e724..365fa8e 100644 --- a/plugins/masters-tournament/masters_renderer.py +++ b/plugins/masters-tournament/masters_renderer.py @@ -851,27 +851,23 @@ def render_countdown(self, days: int, hours: int, minutes: int) -> Optional[Imag right_w = self.width - right_x - 2 right_cx = right_x + right_w // 2 - until_text = unit_text - utw = self._text_width(draw, until_text, self.font_detail) - if utw > right_w: - until_text = "TO MASTERS" - utw = self._text_width(draw, until_text, self.font_detail) - detail_h = self._text_height(draw, "A", self.font_detail) count_h = self._text_height(draw, count_text, self.font_score) - block_h = detail_h + 2 + count_h + 2 + detail_h + # Big number on top, label underneath + block_h = count_h + 3 + detail_h block_y = max(2, (self.height - block_h) // 2) - draw.text((right_cx - utw // 2, block_y), - until_text, fill=COLORS["white"], font=self.font_detail) cw = self._text_width(draw, count_text, self.font_score) - count_y = block_y + detail_h + 2 - self._text_shadow(draw, (right_cx - cw // 2, count_y), + self._text_shadow(draw, (right_cx - cw // 2, block_y), count_text, self.font_score, COLORS["masters_yellow"]) - if unit_text: - uw = self._text_width(draw, unit_text, self.font_detail) - draw.text((right_cx - uw // 2, count_y + count_h + 2), - unit_text, fill=COLORS["light_gray"], font=self.font_detail) + + label = unit_text + lw = self._text_width(draw, label, self.font_detail) + if lw > right_w: + label = "TO MASTERS" + lw = self._text_width(draw, label, self.font_detail) + draw.text((right_cx - lw // 2, block_y + count_h + 3), + label, fill=COLORS["light_gray"], font=self.font_detail) return img # Compact layout: logo centered at top (larger), countdown below @@ -885,28 +881,27 @@ def render_countdown(self, days: int, hours: int, minutes: int) -> Optional[Imag self._draw_logo_with_glow(img, logo, lx, 2) logo_bottom = 2 + logo.height + 2 - # Position text below logo + # Position text below logo: label once, then big countdown remaining = self.height - logo_bottom detail_h = self._text_height(draw, "A", self.font_detail) count_h = self._text_height(draw, count_text, self.font_score) if self.tier == "tiny": - until_text = "TO MASTERS" + label = "TO MASTERS" else: - until_text = unit_text + label = unit_text - # Center the text block in remaining space - text_block_h = detail_h + 2 + count_h + text_block_h = count_h + 2 + detail_h text_y = logo_bottom + max(0, (remaining - text_block_h) // 2) - uw = self._text_width(draw, until_text, self.font_detail) - draw.text(((self.width - uw) // 2, text_y), - until_text, fill=COLORS["white"], font=self.font_detail) - cw = self._text_width(draw, count_text, self.font_score) - self._text_shadow(draw, ((self.width - cw) // 2, text_y + detail_h + 2), + self._text_shadow(draw, ((self.width - cw) // 2, text_y), count_text, self.font_score, COLORS["masters_yellow"]) + lw = self._text_width(draw, label, self.font_detail) + draw.text(((self.width - lw) // 2, text_y + count_h + 2), + label, fill=COLORS["light_gray"], font=self.font_detail) + return img # ═══════════════════════════════════════════════════════════