From d69873ef53f8ded959401cc4e9ae967af6c81c94 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sat, 8 Nov 2025 23:20:28 -0500 Subject: [PATCH 1/3] fix: update the link for the aoc embed thumbnail --- bot/exts/advent_of_code/_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/advent_of_code/_helpers.py b/bot/exts/advent_of_code/_helpers.py index 5313d87..7230cc0 100644 --- a/bot/exts/advent_of_code/_helpers.py +++ b/bot/exts/advent_of_code/_helpers.py @@ -42,7 +42,7 @@ AOC_EMBED_THUMBNAIL = ( "https://raw.githubusercontent.com/python-discord" - "/branding/main/seasonal/christmas/server_icons/festive_256.gif" + "/branding/main/events/christmas/server_icons/festive_256.gif" ) # Create an easy constant for the EST timezone From 217c180b1d508129e750aa44848510edc0ed3bb5 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sun, 9 Nov 2025 00:04:27 -0500 Subject: [PATCH 2/3] show a list of changes for the 2025 season, get rid of the global leaderboard --- bot/constants.py | 1 + bot/exts/advent_of_code/_cog.py | 77 ++++++++++++++++------- bot/exts/advent_of_code/_helpers.py | 2 +- bot/exts/advent_of_code/about.json | 8 +-- bot/exts/advent_of_code/changes_2025.json | 26 ++++++++ 5 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 bot/exts/advent_of_code/changes_2025.json diff --git a/bot/constants.py b/bot/constants.py index 1ee4cb8..75a8578 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -223,6 +223,7 @@ class Colours: python_yellow = 0xFFD43B grass_green = 0x66FF00 gold = 0xE6C200 + aoc_violet = 0x43439D # Git SHA for Sentry diff --git a/bot/exts/advent_of_code/_cog.py b/bot/exts/advent_of_code/_cog.py index 1927eea..4b139eb 100644 --- a/bot/exts/advent_of_code/_cog.py +++ b/bot/exts/advent_of_code/_cog.py @@ -1,6 +1,7 @@ import json from datetime import UTC, datetime, timedelta from pathlib import Path +from typing import Literal import arrow import discord @@ -52,8 +53,13 @@ def __init__(self, bot: SirRobin): self._base_url = f"https://adventofcode.com/{AocConfig.year}" self.global_leaderboard_url = f"https://adventofcode.com/{AocConfig.year}/leaderboard" - self.about_aoc_filepath = Path("./bot/exts/advent_of_code/about.json") - self.cached_about_aoc = self._build_about_embed() + self.aoc_files = Path("./bot/exts/advent_of_code/") + self.cached_about_aoc = self._build_embed_from_json("about") + self.cached_changes = self._build_embed_from_json("changes_2025") + self.cached_no_global = self._build_embed_from_json( + "changes_2025", only_field="What happened to the global leaderboard?" + ) + self.cached_no_global.colour = Colours.soft_red self.scheduler = scheduling.Scheduler(self.__class__.__name__) @@ -410,22 +416,27 @@ async def aoc_leaderboard(self, ctx: commands.Context, *, aoc_name: str | None = await ctx.send(content=f"{header}\n\n{table}", embed=info_embed) return + @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) + @adventofcode_group.command( + name="changes", + brief="Frequently Asked Questions about Advent of Code changes in 2025", + ) + @in_whitelist(channels=AOC_WHITELIST_RESTRICTED, redirect=AOC_REDIRECT) + async def aoc_changes(self, ctx: commands.Context) -> None: + """Get answers to frequently asked questions about Advent of Code changes in 2025.""" + await ctx.send(embed=self.cached_changes) + @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) @adventofcode_group.command( name="global", aliases=("globalboard", "gb"), + hidden=True, # Global leaderboard no longer exists brief="Get a link to the global leaderboard", ) @in_whitelist(channels=AOC_WHITELIST_RESTRICTED, redirect=AOC_REDIRECT) async def aoc_global_leaderboard(self, ctx: commands.Context) -> None: - """Get a link to the global Advent of Code leaderboard.""" - url = self.global_leaderboard_url - global_leaderboard = discord.Embed( - title="Advent of Code — Global Leaderboard", - description=f"You can find the global leaderboard [here]({url})." - ) - global_leaderboard.set_thumbnail(url=_helpers.AOC_EMBED_THUMBNAIL) - await ctx.send(embed=global_leaderboard) + # Same behaviour as aoc changes, but change the title to "where's the global leaderboard" + await ctx.send(embed=self.cached_no_global) @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) @adventofcode_group.command( @@ -479,19 +490,39 @@ async def refresh_leaderboard(self, ctx: commands.Context) -> None: else: await ctx.send("\N{OK Hand Sign} Refreshed leaderboard cache!") - def _build_about_embed(self) -> discord.Embed: + def _build_embed_from_json( + self, file_type: Literal["about","changes_2025"], *, only_field: str | None = None + ) -> discord.Embed: """Build and return the informational "About AoC" embed from the resources file.""" - embed_fields = json.loads(self.about_aoc_filepath.read_text("utf8")) + if file_type == "about": + filepath = self.aoc_files / "about.json" + title = "Advent of Code" + url = self._base_url + colour = Colours.soft_green + + elif file_type == "changes_2025": + filepath = self.aoc_files / "changes_2025.json" + title = "2025 Changes" + url = None + colour = Colours.aoc_violet + else: + raise ValueError("file_type must be either 'about' or 'changes_2025'") - about_embed = discord.Embed( - title=self._base_url, - colour=Colours.soft_green, - url=self._base_url, - timestamp=datetime.now(tz=UTC) - ) - about_embed.set_author(name="Advent of Code", url=self._base_url) - for field in embed_fields: - about_embed.add_field(**field) + embed = discord.Embed(title=title, url=url, colour=colour, timestamp=datetime.now(tz=UTC)) + + embed_fields = json.loads(filepath.read_text("utf8")) + + if only_field: + embed_fields = [field for field in embed_fields if field["name"] == only_field] + if not embed_fields: + raise ValueError(f"No field named '{only_field}' found in {file_type}.json") + embed.title = only_field + embed.description = embed_fields[0]["value"] + else: + for field in embed_fields: + embed.add_field(**field) + + embed.set_author(name="Advent of Code", url=self._base_url) + embed.set_footer(text="Last Updated") - about_embed.set_footer(text="Last Updated") - return about_embed + return embed diff --git a/bot/exts/advent_of_code/_helpers.py b/bot/exts/advent_of_code/_helpers.py index 7230cc0..a8e7885 100644 --- a/bot/exts/advent_of_code/_helpers.py +++ b/bot/exts/advent_of_code/_helpers.py @@ -213,7 +213,7 @@ def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str | raise commands.BadArgument( "Sorry, your profile does not exist in this leaderboard." "\n\n" - "To join our leaderboard, run the command `/aoc join`." + "To join our leaderboard, run the command ." " If you've joined recently, please wait up to 30 minutes for our leaderboard to refresh." ) return "\n".join(leaderboard_lines) diff --git a/bot/exts/advent_of_code/about.json b/bot/exts/advent_of_code/about.json index dd0fe59..f959466 100644 --- a/bot/exts/advent_of_code/about.json +++ b/bot/exts/advent_of_code/about.json @@ -15,13 +15,13 @@ "inline": true }, { - "name": "How does scoring work?", - "value": "For the [global leaderboard](https://adventofcode.com/leaderboard), the first person to get a star first gets 100 points, the second person gets 99 points, and so on down to 1 point at 100th place.\n\nFor private leaderboards, the first person to get a star gets N points, where N is the number of people on the leaderboard. The second person to get the star gets N-1 points and so on and so forth.", + "name": "Is it a competition?", + "value": "In prior years, AoC had a global leaderboard which ranked all participants. Beginning in 2025, the only leaderboards available are private leaderboards. In these private leaderboards, the first person to get a star gets N points, where N is the number of people on the leaderboard. The second person to get the star gets N-1 points and so on and so forth.", "inline": false }, { - "name": "Join our private leaderboard!", - "value": "Come join the Python Discord private leaderboard and compete against other people in the community! Get the join code using `.aoc join` and visit the [private leaderboard page](https://adventofcode.com/leaderboard/private) to join our leaderboard.", + "name": "Join our leaderboard!", + "value": "Come join the Python Discord leaderboard and compete against other people in the community! Get the join code using and visit the [leaderboard page](https://adventofcode.com/leaderboard/private) to join our leaderboard.", "inline": false } ] diff --git a/bot/exts/advent_of_code/changes_2025.json b/bot/exts/advent_of_code/changes_2025.json new file mode 100644 index 0000000..f715cd1 --- /dev/null +++ b/bot/exts/advent_of_code/changes_2025.json @@ -0,0 +1,26 @@ +[ + { + "name": "What changed in Advent of Code 2025?", + "value": "In 2025, Advent of Code made significant changes to its leaderboard system. The global leaderboard was removed, and now only private leaderboards are available. This change aims to create a more inclusive and supportive environment for all participants." + }, + { + "name": "Why did the number of days per event change?", + "value": "[Eric needed a break.](https://hachyderm.io/@ericwastl/115415473413415697) The puzzles still start on December 1st so that the day numbers make sense (Day 1 = Dec 1), and puzzles come out every day (ending mid-December).", + "inline": false + }, + { + "name": "What happened to the global leaderboard?", + "value": "The global leaderboard has been removed starting in 2025 due to DDoS attacks and other issues. Private leaderboards are now the only option for competition.\nYou can join the Python Discord leaderboard with .", + "inline": false + }, + { + "name": "Is there still a way to compete with others?", + "value": "We have our own private leaderboard for the Python Discord community! You can join it using the command and compete with other members of the community.", + "inline": false + }, + { + "name": "Where can I find more information?", + "value": "For more details about the changes in Advent of Code 2025, you can refer to the [official announcement on Reddit](https://www.reddit.com/r/adventofcode/comments/1ocwh04/changes_to_advent_of_code_starting_this_december/) and the [FAQ on the Advent of Code website](https://adventofcode.com/2025/about).", + "inline": false + } +] From 9088a9ffb752a8c21536e9ba28396c01d63b93d1 Mon Sep 17 00:00:00 2001 From: Boris Muratov <8bee278@gmail.com> Date: Sat, 29 Nov 2025 19:23:00 +0200 Subject: [PATCH 3/3] Address CR --- bot/constants.py | 1 - bot/exts/advent_of_code/_cog.py | 88 +++++++++-------------- bot/exts/advent_of_code/about.json | 4 +- bot/exts/advent_of_code/changes_2025.json | 26 ------- 4 files changed, 35 insertions(+), 84 deletions(-) delete mode 100644 bot/exts/advent_of_code/changes_2025.json diff --git a/bot/constants.py b/bot/constants.py index 85dd142..b07573d 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -224,7 +224,6 @@ class Colours: python_yellow = 0xFFD43B grass_green = 0x66FF00 gold = 0xE6C200 - aoc_violet = 0x43439D # Git SHA for Sentry diff --git a/bot/exts/advent_of_code/_cog.py b/bot/exts/advent_of_code/_cog.py index 8faacbe..1cfe20b 100644 --- a/bot/exts/advent_of_code/_cog.py +++ b/bot/exts/advent_of_code/_cog.py @@ -1,7 +1,6 @@ import json from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import Literal import arrow import discord @@ -51,15 +50,10 @@ def __init__(self, bot: SirRobin): self.bot = bot self._base_url = f"https://adventofcode.com/{AocConfig.year}" - self.global_leaderboard_url = f"https://adventofcode.com/{AocConfig.year}/leaderboard" - self.aoc_files = Path("./bot/exts/advent_of_code/") - self.cached_about_aoc = self._build_embed_from_json("about") - self.cached_changes = self._build_embed_from_json("changes_2025") - self.cached_no_global = self._build_embed_from_json( - "changes_2025", only_field="What happened to the global leaderboard?" - ) - self.cached_no_global.colour = Colours.soft_red + self.about_aoc_filepath = Path("./bot/exts/advent_of_code/about.json") + self.cached_about_aoc = self._build_about_embed() + self.cached_no_global = self._build_no_global_leaderboard_embed() self.scheduler = scheduling.Scheduler(self.__class__.__name__) @@ -440,26 +434,14 @@ async def aoc_leaderboard(self, ctx: commands.Context, *, aoc_name: str | None = await ctx.send(content=f"{header}\n\n{table}", embed=info_embed) return - @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) - @adventofcode_group.command( - name="changes", - brief="Frequently Asked Questions about Advent of Code changes in 2025", - ) - @in_whitelist(channels=AOC_WHITELIST_RESTRICTED, redirect=AOC_REDIRECT) - async def aoc_changes(self, ctx: commands.Context) -> None: - """Get answers to frequently asked questions about Advent of Code changes in 2025.""" - await ctx.send(embed=self.cached_changes) - - @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) @adventofcode_group.command( name="global", aliases=("globalboard", "gb"), hidden=True, # Global leaderboard no longer exists - brief="Get a link to the global leaderboard", ) @in_whitelist(channels=AOC_WHITELIST_RESTRICTED, redirect=AOC_REDIRECT) async def aoc_global_leaderboard(self, ctx: commands.Context) -> None: - # Same behaviour as aoc changes, but change the title to "where's the global leaderboard" + """Send an embed notifying about the changes to the global leaderboard.""" await ctx.send(embed=self.cached_no_global) @in_month(Month.DECEMBER, Month.JANUARY, Month.FEBRUARY) @@ -514,39 +496,35 @@ async def refresh_leaderboard(self, ctx: commands.Context) -> None: else: await ctx.send("\N{OK Hand Sign} Refreshed leaderboard cache!") - def _build_embed_from_json( - self, file_type: Literal["about","changes_2025"], *, only_field: str | None = None - ) -> discord.Embed: + def _build_about_embed(self) -> discord.Embed: """Build and return the informational "About AoC" embed from the resources file.""" - if file_type == "about": - filepath = self.aoc_files / "about.json" - title = "Advent of Code" - url = self._base_url - colour = Colours.soft_green - - elif file_type == "changes_2025": - filepath = self.aoc_files / "changes_2025.json" - title = "2025 Changes" - url = None - colour = Colours.aoc_violet - else: - raise ValueError("file_type must be either 'about' or 'changes_2025'") + embed_fields = json.loads(self.about_aoc_filepath.read_text("utf8")) - embed = discord.Embed(title=title, url=url, colour=colour, timestamp=datetime.now(tz=UTC)) - - embed_fields = json.loads(filepath.read_text("utf8")) - - if only_field: - embed_fields = [field for field in embed_fields if field["name"] == only_field] - if not embed_fields: - raise ValueError(f"No field named '{only_field}' found in {file_type}.json") - embed.title = only_field - embed.description = embed_fields[0]["value"] - else: - for field in embed_fields: - embed.add_field(**field) - - embed.set_author(name="Advent of Code", url=self._base_url) - embed.set_footer(text="Last Updated") + about_embed = discord.Embed( + title=self._base_url, + colour=Colours.soft_green, + url=self._base_url, + ) + about_embed.set_author(name="Advent of Code", url=self._base_url) + for field in embed_fields: + about_embed.add_field(**field) + + about_embed.set_footer(text="Last Updated") + return about_embed + + @staticmethod + def _build_no_global_leaderboard_embed() -> discord.Embed: + """Build and return an embed notifying about the changes to the global leaderboard.""" + faq_link = "https://adventofcode.com/2025/about#faq_leaderboard" + description = ( + f"To read about this change, head over to the [AoC FAQ]({faq_link}).\n\n" + "You can still access the global leaderboards of previous years by heading over to " + "https://adventofcode.com/events, choosing the desired year, and heading over to " + "the `[Leaderboards]` tab." + ) - return embed + return discord.Embed( + title="The global leaderboard is no more", + description=description, + colour=Colours.soft_red, + ) diff --git a/bot/exts/advent_of_code/about.json b/bot/exts/advent_of_code/about.json index f959466..63c7d28 100644 --- a/bot/exts/advent_of_code/about.json +++ b/bot/exts/advent_of_code/about.json @@ -15,8 +15,8 @@ "inline": true }, { - "name": "Is it a competition?", - "value": "In prior years, AoC had a global leaderboard which ranked all participants. Beginning in 2025, the only leaderboards available are private leaderboards. In these private leaderboards, the first person to get a star gets N points, where N is the number of people on the leaderboard. The second person to get the star gets N-1 points and so on and so forth.", + "name": "How does scoring work?", + "value": "AoC has private leaderboards. In these, the first person to get a star gets N points, where N is the number of people on the leaderboard. The second person to get the star gets N-1 points and so on and so forth. As the size of a leaderboard is limited, and Python Discord has many people who want to participate, we merge several leaderboards into one.\n\nTherefore, while you may see your standing in a specific leaderboard on the website, to get your total Python Discord standings you need to run the `&aoc lb` command.", "inline": false }, { diff --git a/bot/exts/advent_of_code/changes_2025.json b/bot/exts/advent_of_code/changes_2025.json deleted file mode 100644 index f715cd1..0000000 --- a/bot/exts/advent_of_code/changes_2025.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "name": "What changed in Advent of Code 2025?", - "value": "In 2025, Advent of Code made significant changes to its leaderboard system. The global leaderboard was removed, and now only private leaderboards are available. This change aims to create a more inclusive and supportive environment for all participants." - }, - { - "name": "Why did the number of days per event change?", - "value": "[Eric needed a break.](https://hachyderm.io/@ericwastl/115415473413415697) The puzzles still start on December 1st so that the day numbers make sense (Day 1 = Dec 1), and puzzles come out every day (ending mid-December).", - "inline": false - }, - { - "name": "What happened to the global leaderboard?", - "value": "The global leaderboard has been removed starting in 2025 due to DDoS attacks and other issues. Private leaderboards are now the only option for competition.\nYou can join the Python Discord leaderboard with .", - "inline": false - }, - { - "name": "Is there still a way to compete with others?", - "value": "We have our own private leaderboard for the Python Discord community! You can join it using the command and compete with other members of the community.", - "inline": false - }, - { - "name": "Where can I find more information?", - "value": "For more details about the changes in Advent of Code 2025, you can refer to the [official announcement on Reddit](https://www.reddit.com/r/adventofcode/comments/1ocwh04/changes_to_advent_of_code_starting_this_december/) and the [FAQ on the Advent of Code website](https://adventofcode.com/2025/about).", - "inline": false - } -]