diff options
-rw-r--r-- | bot/constants.py | 2 | ||||
-rw-r--r-- | bot/resources/advent_of_code/about.json | 2 | ||||
-rw-r--r-- | bot/resources/valentines/valenstates.json | 122 | ||||
-rw-r--r-- | bot/seasons/christmas/adventofcode.py | 11 | ||||
-rw-r--r-- | bot/seasons/evergreen/__init__.py | 2 | ||||
-rw-r--r-- | bot/seasons/season.py | 27 | ||||
-rw-r--r-- | bot/seasons/valentines/myvalenstate.py | 85 |
7 files changed, 236 insertions, 15 deletions
diff --git a/bot/constants.py b/bot/constants.py index cc04fd98..b19d494b 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -15,7 +15,7 @@ log = logging.getLogger(__name__) class AdventOfCode: leaderboard_cache_age_threshold_seconds = 3600 leaderboard_id = 363275 - leaderboard_join_code = "363275-442b6939" + leaderboard_join_code = str(environ.get("AOC_JOIN_CODE", None)) leaderboard_max_displayed_members = 10 year = 2018 channel_id = int(environ.get("AOC_CHANNEL_ID", 517745814039166986)) diff --git a/bot/resources/advent_of_code/about.json b/bot/resources/advent_of_code/about.json index 3fe6fcc9..4abf9145 100644 --- a/bot/resources/advent_of_code/about.json +++ b/bot/resources/advent_of_code/about.json @@ -21,7 +21,7 @@ }, { "name": "Join our private leaderboard!", - "value": "In addition to the global leaderboard, AoC also offers private leaderboards, where you can compete against a smaller group of friends!\n\nHead over to AoC's [private leaderboard page](https://adventofcode.com/leaderboard/private) and enter code `363275-442b6939` to join the PyDis private leaderboard!", + "value": "In addition to the global leaderboard, AoC also offers private leaderboards, where you can compete against a smaller group of friends!\n\nGet the join code using `.aoc join` and head over to AoC's [private leaderboard page](https://adventofcode.com/leaderboard/private) to join the PyDis private leaderboard!", "inline": false } ]
\ No newline at end of file diff --git a/bot/resources/valentines/valenstates.json b/bot/resources/valentines/valenstates.json new file mode 100644 index 00000000..06cbb2e5 --- /dev/null +++ b/bot/resources/valentines/valenstates.json @@ -0,0 +1,122 @@ +{ + "Australia": { + "text": "Australia is the oldest, flattest and driest inhabited continent on earth. It is one of the 18 megadiverse countries, featuring a wide variety of plants and animals, the most iconic ones being the koalas and kangaroos, as well as its deadly wildlife and trees falling under the Eucalyptus genus.", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/Flag_of_Australia_%28converted%29.svg/1920px-Flag_of_Australia_%28converted%29.svg.png" + }, + "Austria": { + "text": "Austria is part of the european continent, lying in the alps. Due to its location, Austria possesses a variety of very tall mountains like the Großglockner (3798 m) or the Wildspitze (3772 m).", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_Austria.svg/1920px-Flag_of_Austria.svg.png" + }, + "Brazil": { + "text": "Being the largest and most populated country in South and Latin America, Brazil, as one of the 18 megadiverse countries, features a wide variety of plants and animals, especially in the Amazon rainforest, the most biodiverse rainforest in the world.", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/0/05/Flag_of_Brazil.svg/1280px-Flag_of_Brazil.svg.png" + }, + "Canada": { + "text": "Canada is the second-largest country in the world measured by total area, only surpassed by Russia. It's widely known for its astonishing national parks.", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Flag_of_Canada_%28Pantone%29.svg/1920px-Flag_of_Canada_%28Pantone%29.svg.png" + }, + "Croatia": { + "text": "Croatia is a country at the crossroads of Central and Southeast Europe, mostly known for its beautiful beaches and waters.", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Flag_of_Croatia.svg/1920px-Flag_of_Croatia.svg.png" + }, + "England": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/b/be/Flag_of_England.svg/1920px-Flag_of_England.svg.png" + }, + "Finland": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Finland.svg/1920px-Flag_of_Finland.svg.png" + }, + "France": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/c/c3/Flag_of_France.svg/1920px-Flag_of_France.svg.png" + }, + "Germany": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1920px-Flag_of_Germany.svg.png" + }, + "Greece": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Greece.svg/1920px-Flag_of_Greece.svg.png" + }, + "Iceland": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Iceland.svg/1280px-Flag_of_Iceland.svg.png" + }, + "India": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/4/41/Flag_of_India.svg/1920px-Flag_of_India.svg.png" + }, + "Indonesia": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Indonesia.svg/1920px-Flag_of_Indonesia.svg.png" + }, + "Ireland": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Ireland.svg/1920px-Flag_of_Ireland.svg.png" + }, + "Italy": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/0/03/Flag_of_Italy.svg/1920px-Flag_of_Italy.svg.png" + }, + "Mexico": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Flag_of_Mexico.svg/1920px-Flag_of_Mexico.svg.png" + }, + "New Zealand": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_New_Zealand.svg/1920px-Flag_of_New_Zealand.svg.png" + }, + "Norway": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Flag_of_Norway.svg/1280px-Flag_of_Norway.svg.png" + }, + "Peru": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Flag_of_Peru.svg/1920px-Flag_of_Peru.svg.png" + }, + "Portugal": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Portugal.svg/1920px-Flag_of_Portugal.svg.png" + }, + "Scotland": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_Scotland.svg/1920px-Flag_of_Scotland.svg.png" + }, + "Slovenia": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Flag_of_Slovenia.svg/1920px-Flag_of_Slovenia.svg.png" + }, + "South Africa": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Flag_of_South_Africa.svg/1920px-Flag_of_South_Africa.svg.png" + }, + "Spain": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/9/9a/Flag_of_Spain.svg/1920px-Flag_of_Spain.svg.png" + }, + "Sweden": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Flag_of_Sweden.svg/1920px-Flag_of_Sweden.svg.png" + }, + "Switzerland": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_Switzerland_%28Pantone%29.svg/1024px-Flag_of_Switzerland_%28Pantone%29.svg.png" + }, + "Turkey": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Flag_of_Turkey.svg/1920px-Flag_of_Turkey.svg.png" + }, + "United States": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/1920px-Flag_of_the_United_States.svg.png" + }, + "Vietnam": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Vietnam.svg/1920px-Flag_of_Vietnam.svg.png" + }, + "Wales": { + "text": "", + "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Flag_of_Wales_%281959%E2%80%93present%29.svg/1920px-Flag_of_Wales_%281959%E2%80%93present%29.svg.png" + } +}
\ No newline at end of file diff --git a/bot/seasons/christmas/adventofcode.py b/bot/seasons/christmas/adventofcode.py index 3b199a4a..a926a6cb 100644 --- a/bot/seasons/christmas/adventofcode.py +++ b/bot/seasons/christmas/adventofcode.py @@ -205,14 +205,21 @@ class AdventOfCode: @adventofcode_group.command(name="join", aliases=("j",), brief="Learn how to join PyDis' private AoC leaderboard") async def join_leaderboard(self, ctx: commands.Context): """ - Retrieve the link to join the PyDis AoC private leaderboard + DM the user the information for joining the PyDis AoC private leaderboard """ + author = ctx.message.author + log.info(f"{author.name} ({author.id}) has requested the PyDis AoC leaderboard code") + info_str = ( "Head over to https://adventofcode.com/leaderboard/private " f"with code `{AocConfig.leaderboard_join_code}` to join the PyDis private leaderboard!" ) - await ctx.send(info_str) + try: + await author.send(info_str) + except discord.errors.Forbidden: + log.debug(f"{author.name} ({author.id}) has disabled DMs from server members") + await ctx.send(f":x: {author.mention}, please (temporarily) enable DMs to receive the join code") @adventofcode_group.command( name="leaderboard", diff --git a/bot/seasons/evergreen/__init__.py b/bot/seasons/evergreen/__init__.py index db5b5684..db610e7c 100644 --- a/bot/seasons/evergreen/__init__.py +++ b/bot/seasons/evergreen/__init__.py @@ -2,4 +2,4 @@ from bot.seasons import SeasonBase class Evergreen(SeasonBase): - pass + bot_icon = "/logos/logo_seasonal/evergreen/logo_evergreen.png" diff --git a/bot/seasons/season.py b/bot/seasons/season.py index e59949d7..ae12057f 100644 --- a/bot/seasons/season.py +++ b/bot/seasons/season.py @@ -90,6 +90,7 @@ class SeasonBase: colour: Optional[int] = None icon: str = "/logos/logo_full/logo_full.png" + bot_icon: Optional[str] = None date_format: str = "%d/%m/%Y" @@ -151,10 +152,11 @@ class SeasonBase: return f"New Season, {self.name_clean}!" - async def get_icon(self) -> bytes: + async def get_icon(self, avatar: bool = False) -> bytes: """ Retrieves the icon image from the branding repository, using the - defined icon attribute for the season. + defined icon attribute for the season. If `avatar` is True, uses + optional bot-only avatar icon if present. The icon attribute must provide the url path, starting from the master branch base url, including the starting slash: @@ -162,7 +164,11 @@ class SeasonBase: """ base_url = "https://raw.githubusercontent.com/python-discord/branding/master" - full_url = base_url + self.icon + if avatar: + icon = self.bot_icon or self.icon + else: + icon = self.icon + full_url = base_url + icon log.debug(f"Getting icon from: {full_url}") async with bot.http_session.get(full_url) as resp: return await resp.read() @@ -217,17 +223,17 @@ class SeasonBase: old_avatar = bot.user.avatar # attempt the change - log.debug(f"Changing avatar to {self.icon}") - icon = await self.get_icon() + log.debug(f"Changing avatar to {self.bot_icon or self.icon}") + icon = await self.get_icon(avatar=True) with contextlib.suppress(discord.HTTPException, asyncio.TimeoutError): async with async_timeout.timeout(5): await bot.user.edit(avatar=icon) if bot.user.avatar != old_avatar: - log.debug(f"Avatar changed to {self.icon}") + log.debug(f"Avatar changed to {self.bot_icon or self.icon}") return True - log.warning(f"Changing avatar failed: {self.icon}") + log.warning(f"Changing avatar failed: {self.bot_icon or self.icon}") return False async def apply_server_icon(self) -> bool: @@ -334,12 +340,13 @@ class SeasonBase: if not Client.debug: log.info("Applying avatar.") await self.apply_avatar() - log.info("Applying server icon.") - await self.apply_server_icon() if username_changed: + log.info("Applying server icon.") + await self.apply_server_icon() log.info(f"Announcing season {self.name}.") await self.announce_season() else: + log.info(f"Skipping server icon change due to username not being changed.") log.info(f"Skipping season announcement due to username not being changed.") await bot.send_log("SeasonalBot Loaded!", f"Active Season: **{self.name_clean}**") @@ -465,7 +472,7 @@ class SeasonManager: # report back details season_name = type(self.season).__name__ embed = discord.Embed( - description=f"**Season:** {season_name}\n**Avatar:** {self.season.icon}", + description=f"**Season:** {season_name}\n**Avatar:** {self.season.bot_icon or self.season.icon}", colour=colour ) embed.set_author(name=title) diff --git a/bot/seasons/valentines/myvalenstate.py b/bot/seasons/valentines/myvalenstate.py new file mode 100644 index 00000000..9f06553d --- /dev/null +++ b/bot/seasons/valentines/myvalenstate.py @@ -0,0 +1,85 @@ +import collections +import json +import logging +from pathlib import Path +from random import choice + +import discord +from discord.ext import commands + +from bot.constants import Colours + +log = logging.getLogger(__name__) + +with open(Path('bot', 'resources', 'valentines', 'valenstates.json'), 'r') as file: + STATES = json.load(file) + + +class MyValenstate: + def __init__(self, bot): + self.bot = bot + + def levenshtein(self, source, goal): + """ + Calculates the Levenshtein Distance between source and goal. + """ + if len(source) < len(goal): + return self.levenshtein(goal, source) + if len(source) == 0: + return len(goal) + if len(goal) == 0: + return len(source) + + pre_row = list(range(0, len(source) + 1)) + for i, source_c in enumerate(source): + cur_row = [i + 1] + for j, goal_c in enumerate(goal): + if source_c != goal_c: + cur_row.append(min(pre_row[j], pre_row[j + 1], cur_row[j]) + 1) + else: + cur_row.append(min(pre_row[j], pre_row[j + 1], cur_row[j])) + pre_row = cur_row + return pre_row[-1] + + @commands.command() + async def myvalenstate(self, ctx, *, name=None): + eq_chars = collections.defaultdict(int) + if name is None: + author = ctx.message.author.name.lower().replace(' ', '') + else: + author = name.lower().replace(' ', '') + + for state in STATES.keys(): + lower_state = state.lower().replace(' ', '') + eq_chars[state] = self.levenshtein(author, lower_state) + + matches = [x for x, y in eq_chars.items() if y == min(eq_chars.values())] + valenstate = choice(matches) + matches.remove(valenstate) + + embed_title = "But there are more!" + if len(matches) > 1: + leftovers = f"{', '.join(matches[:len(matches)-2])}, and {matches[len(matches)-1]}" + embed_text = f"You have {len(matches)} more matches, these being {leftovers}." + elif len(matches) == 1: + embed_title = "But there's another one!" + leftovers = str(matches) + embed_text = f"You have another match, this being {leftovers}." + else: + embed_title = "You have a true match!" + embed_text = "This state is your true Valenstate! There are no states that would suit" \ + " you better" + + embed = discord.Embed( + title=f'Your Valenstate is {valenstate} \u2764', + description=f'{STATES[valenstate]["text"]}', + colour=Colours.pink + ) + embed.add_field(name=embed_title, value=embed_text) + embed.set_image(url=STATES[valenstate]["flag"]) + await ctx.channel.send(embed=embed) + + +def setup(bot): + bot.add_cog(MyValenstate(bot)) + log.debug("MyValenstate cog loaded") |