diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/requirements.txt b/requirements.txt
index dc1dbf7..4bb7724 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
-hikari==2.0.0.dev122
-hikari-arc==1.1.0
-ruff==0.2.0
-pre-commit==3.6.0
-python-dotenv==1.0.1
\ No newline at end of file
+hikari==2.0.0.dev122
+hikari-arc==1.1.0
+ruff==0.2.0
+pre-commit==3.6.0
+python-dotenv==1.0.1
diff --git a/src/__main__.py b/src/__main__.py
index 4db49ff..41c39ff 100644
--- a/src/__main__.py
+++ b/src/__main__.py
@@ -1,6 +1,6 @@
-from hikari import Activity, ActivityType
-
-from src.bot import bot
-
-if __name__ == "__main__":
- bot.run(activity=Activity(name="Webgroup issues", type=ActivityType.WATCHING))
+from hikari import Activity, ActivityType
+
+from src.bot import bot
+
+if __name__ == "__main__":
+ bot.run(activity=Activity(name="Webgroup issues", type=ActivityType.WATCHING))
diff --git a/src/bot.py b/src/bot.py
index e078fcf..1f8a241 100644
--- a/src/bot.py
+++ b/src/bot.py
@@ -1,36 +1,36 @@
-import logging
-import sys
-
-import arc
-import hikari
-
-from src.config import DEBUG, TOKEN
-
-if TOKEN is None:
- print("TOKEN environment variable not set. Exiting.")
- sys.exit(1)
-
-bot = hikari.GatewayBot(
- token=TOKEN,
- banner=None,
- intents=hikari.Intents.ALL_UNPRIVILEGED | hikari.Intents.MESSAGE_CONTENT,
- logs="DEBUG" if DEBUG else "INFO",
-)
-
-logging.info(f"Debug mode is {DEBUG}; You can safely ignore this.")
-
-client = arc.GatewayClient(bot, is_dm_enabled=False)
-client.load_extensions_from("./src/extensions/")
-
-
-@client.set_error_handler
-async def error_handler(ctx: arc.GatewayContext, exc: Exception) -> None:
- if DEBUG:
- message = f"```{exc}```"
- else:
- message = "If this persists, create an issue at ."
-
- await ctx.respond(f"❌ Blockbot encountered an unhandled exception. {message}")
- logging.error(exc)
-
- raise exc
+import logging
+import sys
+
+import arc
+import hikari
+
+from src.config import DEBUG, TOKEN
+
+if TOKEN is None:
+ print("TOKEN environment variable not set. Exiting.")
+ sys.exit(1)
+
+bot = hikari.GatewayBot(
+ token=TOKEN,
+ banner=None,
+ intents=hikari.Intents.ALL_UNPRIVILEGED | hikari.Intents.MESSAGE_CONTENT,
+ logs="DEBUG" if DEBUG else "INFO",
+)
+
+logging.info(f"Debug mode is {DEBUG}; You can safely ignore this.")
+
+client = arc.GatewayClient(bot, is_dm_enabled=False)
+client.load_extensions_from("./src/extensions/")
+
+
+@client.set_error_handler
+async def error_handler(ctx: arc.GatewayContext, exc: Exception) -> None:
+ if DEBUG:
+ message = f"```{exc}```"
+ else:
+ message = "If this persists, create an issue at ."
+
+ await ctx.respond(f"❌ Blockbot encountered an unhandled exception. {message}")
+ logging.error(exc)
+
+ raise exc
diff --git a/src/config.py b/src/config.py
index 42cc71a..e4d66f9 100644
--- a/src/config.py
+++ b/src/config.py
@@ -1,10 +1,10 @@
-import os
-
-from dotenv import load_dotenv
-
-load_dotenv()
-
-TOKEN = os.environ.get("TOKEN") # required
-DEBUG = os.environ.get("DEBUG", False)
-
-CHANNEL_IDS: dict[str, int] = {"lobby": 627542044390457350}
+import os
+
+from dotenv import load_dotenv
+
+load_dotenv()
+
+TOKEN = os.environ.get("TOKEN") # required
+DEBUG = os.environ.get("DEBUG", False)
+
+CHANNEL_IDS: dict[str, int] = {"lobby": 627542044390457350}
diff --git a/src/extensions/boosts.py b/src/extensions/boosts.py
index 5fc6c7d..6222c48 100644
--- a/src/extensions/boosts.py
+++ b/src/extensions/boosts.py
@@ -1,56 +1,60 @@
-import arc
-import hikari
-
-from src.config import CHANNEL_IDS
-from src.utils import get_guild
-
-plugin = arc.GatewayPlugin(name="Boosts")
-
-BOOST_TIERS: list[hikari.MessageType] = [
- hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1,
- hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2,
- hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3,
-]
-
-BOOST_MESSAGE_TYPES: list[hikari.MessageType] = BOOST_TIERS + [hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION]
-
-
-def build_boost_message(
- message_type: hikari.MessageType | int,
- number_of_boosts: str | None,
- booster_user: hikari.Member,
- guild: hikari.Guild,
-) -> str:
- assert message_type in BOOST_MESSAGE_TYPES
-
- base_message = f"{booster_user.display_name} just boosted the server"
- multiple_boosts_message = f" **{number_of_boosts}** times" if number_of_boosts else ""
-
- message = base_message + multiple_boosts_message + "!"
-
- if message_type in BOOST_TIERS:
- count = BOOST_TIERS.index(message_type) + 1
- message += f"\n{guild.name} has reached **Level {count}!**"
-
- return message
-
-
-@plugin.listen()
-async def on_message(event: hikari.GuildMessageCreateEvent) -> None:
- if event.message.type not in BOOST_MESSAGE_TYPES:
- return
-
- assert event.member is not None
- message = build_boost_message(
- event.message.type,
- number_of_boosts=event.content,
- booster_user=event.member,
- guild=await get_guild(plugin.client, event),
- )
-
- await plugin.client.rest.create_message(CHANNEL_IDS["lobby"], content=message)
-
-
-@arc.loader
-def loader(client: arc.GatewayClient) -> None:
- client.add_plugin(plugin)
+import arc
+import hikari
+
+from src.config import CHANNEL_IDS
+from src.utils import get_guild
+
+plugin = arc.GatewayPlugin(name="Boosts")
+
+BOOST_TIERS: list[hikari.MessageType] = [
+ hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1,
+ hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2,
+ hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3,
+]
+
+BOOST_MESSAGE_TYPES: list[hikari.MessageType] = BOOST_TIERS + [
+ hikari.MessageType.USER_PREMIUM_GUILD_SUBSCRIPTION
+]
+
+
+def build_boost_message(
+ message_type: hikari.MessageType | int,
+ number_of_boosts: str | None,
+ booster_user: hikari.Member,
+ guild: hikari.Guild,
+) -> str:
+ assert message_type in BOOST_MESSAGE_TYPES
+
+ base_message = f"{booster_user.display_name} just boosted the server"
+ multiple_boosts_message = (
+ f" **{number_of_boosts}** times" if number_of_boosts else ""
+ )
+
+ message = base_message + multiple_boosts_message + "!"
+
+ if message_type in BOOST_TIERS:
+ count = BOOST_TIERS.index(message_type) + 1
+ message += f"\n{guild.name} has reached **Level {count}!**"
+
+ return message
+
+
+@plugin.listen()
+async def on_message(event: hikari.GuildMessageCreateEvent) -> None:
+ if event.message.type not in BOOST_MESSAGE_TYPES:
+ return
+
+ assert event.member is not None
+ message = build_boost_message(
+ event.message.type,
+ number_of_boosts=event.content,
+ booster_user=event.member,
+ guild=await get_guild(plugin.client, event),
+ )
+
+ await plugin.client.rest.create_message(CHANNEL_IDS["lobby"], content=message)
+
+
+@arc.loader
+def loader(client: arc.GatewayClient) -> None:
+ client.add_plugin(plugin)
diff --git a/src/extensions/hello_world.py b/src/extensions/hello_world.py
index be97d92..0de108a 100644
--- a/src/extensions/hello_world.py
+++ b/src/extensions/hello_world.py
@@ -1,83 +1,91 @@
-"""
-Example extension with simple commands
-"""
-
-import arc
-import hikari
-
-plugin = arc.GatewayPlugin(name="Hello World")
-
-
-@plugin.include
-@arc.slash_command("hello", "Say hello!")
-async def hello(ctx: arc.GatewayContext) -> None:
- """A simple hello world command"""
- await ctx.respond("Hello from hikari!")
-
-
-group = plugin.include_slash_group("base_command", "A base command, to expand on")
-
-
-@group.include
-@arc.slash_subcommand("sub_command", "A sub command, to expand on")
-async def sub_command(ctx: arc.GatewayContext) -> None:
- """A simple sub command"""
- await ctx.respond("Hello, world! This is a sub command")
-
-
-@plugin.include
-@arc.slash_command("options", "A command with options")
-async def options(
- ctx: arc.GatewayContext,
- option_str: arc.Option[str, arc.StrParams("A string option")],
- option_int: arc.Option[int, arc.IntParams("An integer option")],
- option_attachment: arc.Option[hikari.Attachment, arc.AttachmentParams("An attachment option")],
-) -> None:
- """A command with lots of options"""
- embed = hikari.Embed(title="There are a lot of options here", description="Maybe too many", colour=0x5865F2)
- embed.set_image(option_attachment)
- embed.add_field("String option", option_str, inline=False)
- embed.add_field("Integer option", str(option_int), inline=False)
- await ctx.respond(embed=embed)
-
-
-@plugin.include
-@arc.slash_command("components", "A command with components")
-async def components(ctx: arc.GatewayContext) -> None:
- """A command with components"""
- builder = ctx.client.rest.build_message_action_row()
- select_menu = builder.add_text_menu("select_me", placeholder="I wonder what this does", min_values=1, max_values=2)
- for opt in ("Select me!", "No, select me!", "Select me too!"):
- select_menu.add_option(opt, opt)
-
- button = ctx.client.rest.build_message_action_row().add_interactive_button(
- hikari.ButtonStyle.PRIMARY, "click_me", label="Click me!"
- )
-
- await ctx.respond("Here are some components", components=[builder, button])
-
-
-@plugin.listen()
-async def on_interaction(event: hikari.InteractionCreateEvent) -> None:
- interaction = event.interaction
-
- # Discussions are underway for allowing to listen for a "ComponentInteractionEvent" directly
- # instead of doing this manual filtering: https://github.com/hikari-py/hikari/issues/1777
- if not isinstance(interaction, hikari.ComponentInteraction):
- return
-
- if interaction.custom_id == "click_me":
- await interaction.create_initial_response(
- hikari.ResponseType.MESSAGE_CREATE,
- f"{interaction.user.mention}, you clicked me!",
- )
- elif interaction.custom_id == "select_me":
- await interaction.create_initial_response(
- hikari.ResponseType.MESSAGE_CREATE,
- f"{interaction.user.mention}, you selected {' '.join(interaction.values)}",
- )
-
-
-@arc.loader
-def loader(client: arc.GatewayClient) -> None:
- client.add_plugin(plugin)
+"""
+Example extension with simple commands
+"""
+
+import arc
+import hikari
+
+plugin = arc.GatewayPlugin(name="Hello World")
+
+
+@plugin.include
+@arc.slash_command("hello", "Say hello!")
+async def hello(ctx: arc.GatewayContext) -> None:
+ """A simple hello world command"""
+ await ctx.respond("Hello from hikari!")
+
+
+group = plugin.include_slash_group("base_command", "A base command, to expand on")
+
+
+@group.include
+@arc.slash_subcommand("sub_command", "A sub command, to expand on")
+async def sub_command(ctx: arc.GatewayContext) -> None:
+ """A simple sub command"""
+ await ctx.respond("Hello, world! This is a sub command")
+
+
+@plugin.include
+@arc.slash_command("options", "A command with options")
+async def options(
+ ctx: arc.GatewayContext,
+ option_str: arc.Option[str, arc.StrParams("A string option")],
+ option_int: arc.Option[int, arc.IntParams("An integer option")],
+ option_attachment: arc.Option[
+ hikari.Attachment, arc.AttachmentParams("An attachment option")
+ ],
+) -> None:
+ """A command with lots of options"""
+ embed = hikari.Embed(
+ title="There are a lot of options here",
+ description="Maybe too many",
+ colour=0x5865F2,
+ )
+ embed.set_image(option_attachment)
+ embed.add_field("String option", option_str, inline=False)
+ embed.add_field("Integer option", str(option_int), inline=False)
+ await ctx.respond(embed=embed)
+
+
+@plugin.include
+@arc.slash_command("components", "A command with components")
+async def components(ctx: arc.GatewayContext) -> None:
+ """A command with components"""
+ builder = ctx.client.rest.build_message_action_row()
+ select_menu = builder.add_text_menu(
+ "select_me", placeholder="I wonder what this does", min_values=1, max_values=2
+ )
+ for opt in ("Select me!", "No, select me!", "Select me too!"):
+ select_menu.add_option(opt, opt)
+
+ button = ctx.client.rest.build_message_action_row().add_interactive_button(
+ hikari.ButtonStyle.PRIMARY, "click_me", label="Click me!"
+ )
+
+ await ctx.respond("Here are some components", components=[builder, button])
+
+
+@plugin.listen()
+async def on_interaction(event: hikari.InteractionCreateEvent) -> None:
+ interaction = event.interaction
+
+ # Discussions are underway for allowing to listen for a "ComponentInteractionEvent" directly
+ # instead of doing this manual filtering: https://github.com/hikari-py/hikari/issues/1777
+ if not isinstance(interaction, hikari.ComponentInteraction):
+ return
+
+ if interaction.custom_id == "click_me":
+ await interaction.create_initial_response(
+ hikari.ResponseType.MESSAGE_CREATE,
+ f"{interaction.user.mention}, you clicked me!",
+ )
+ elif interaction.custom_id == "select_me":
+ await interaction.create_initial_response(
+ hikari.ResponseType.MESSAGE_CREATE,
+ f"{interaction.user.mention}, you selected {' '.join(interaction.values)}",
+ )
+
+
+@arc.loader
+def loader(client: arc.GatewayClient) -> None:
+ client.add_plugin(plugin)
diff --git a/src/extensions/uptime.py b/src/extensions/uptime.py
index c3ffba8..5afa95a 100644
--- a/src/extensions/uptime.py
+++ b/src/extensions/uptime.py
@@ -1,29 +1,29 @@
-from datetime import datetime
-
-import arc
-
-start_time = datetime.now()
-
-plugin = arc.GatewayPlugin("Blockbot Uptime")
-
-
-@plugin.include
-@arc.slash_command("uptime", "Show formatted uptime of Blockbot")
-async def uptime(ctx: arc.GatewayContext) -> None:
- up_time = datetime.now() - start_time
- d = up_time.days
- h, ms = divmod(up_time.seconds, 3600)
- m, s = divmod(ms, 60)
-
- def format(val: int, s: str):
- return f"{val} {s}{'s' if val != 1 else ''}"
-
- message_parts = [(d, "day"), (h, "hour"), (m, "minute"), (s, "second")]
- formatted_parts = [format(val, str) for val, str in message_parts if val]
-
- await ctx.respond(f"Uptime: **{', '.join(formatted_parts)}**")
-
-
-@arc.loader
-def loader(client: arc.GatewayClient) -> None:
- client.add_plugin(plugin)
+from datetime import datetime
+
+import arc
+
+start_time = datetime.now()
+
+plugin = arc.GatewayPlugin("Blockbot Uptime")
+
+
+@plugin.include
+@arc.slash_command("uptime", "Show formatted uptime of Blockbot")
+async def uptime(ctx: arc.GatewayContext) -> None:
+ up_time = datetime.now() - start_time
+ d = up_time.days
+ h, ms = divmod(up_time.seconds, 3600)
+ m, s = divmod(ms, 60)
+
+ def format(val: int, s: str):
+ return f"{val} {s}{'s' if val != 1 else ''}"
+
+ message_parts = [(d, "day"), (h, "hour"), (m, "minute"), (s, "second")]
+ formatted_parts = [format(val, str) for val, str in message_parts if val]
+
+ await ctx.respond(f"Uptime: **{', '.join(formatted_parts)}**")
+
+
+@arc.loader
+def loader(client: arc.GatewayClient) -> None:
+ client.add_plugin(plugin)
diff --git a/src/extensions/user_roles.py b/src/extensions/user_roles.py
index 4c14d53..7653e3e 100644
--- a/src/extensions/user_roles.py
+++ b/src/extensions/user_roles.py
@@ -25,11 +25,19 @@ async def add_role(
assert ctx.member
if int(role) in ctx.member.role_ids:
- await ctx.respond(f"You already have the {role_mention(role)} role.", flags=hikari.MessageFlag.EPHEMERAL)
+ await ctx.respond(
+ f"You already have the {role_mention(role)} role.",
+ flags=hikari.MessageFlag.EPHEMERAL,
+ )
return
- await ctx.client.rest.add_role_to_member(ctx.guild_id, ctx.author, int(role), reason="Self-service role.")
- await ctx.respond(f"Done! Added {role_mention(role)} to your roles.", flags=hikari.MessageFlag.EPHEMERAL)
+ await ctx.client.rest.add_role_to_member(
+ ctx.guild_id, ctx.author, int(role), reason="Self-service role."
+ )
+ await ctx.respond(
+ f"Done! Added {role_mention(role)} to your roles.",
+ flags=hikari.MessageFlag.EPHEMERAL,
+ )
@role.include
@@ -42,13 +50,19 @@ async def remove_role(
assert ctx.member
if int(role) not in ctx.member.role_ids:
- await ctx.respond(f"You don't have the {role_mention(role)} role.", flags=hikari.MessageFlag.EPHEMERAL)
+ await ctx.respond(
+ f"You don't have the {role_mention(role)} role.",
+ flags=hikari.MessageFlag.EPHEMERAL,
+ )
return
await ctx.client.rest.remove_role_from_member(
ctx.guild_id, ctx.author, int(role), reason=f"{ctx.author} removed role."
)
- await ctx.respond(f"Done! Removed {role_mention(role)} from your roles.", flags=hikari.MessageFlag.EPHEMERAL)
+ await ctx.respond(
+ f"Done! Removed {role_mention(role)} from your roles.",
+ flags=hikari.MessageFlag.EPHEMERAL,
+ )
@role.set_error_handler
@@ -64,7 +78,9 @@ async def role_error_handler(ctx: arc.GatewayContext, exc: Exception) -> None:
return
if isinstance(exc, hikari.NotFoundError):
- await ctx.respond("❌ Blockbot can't find that role.", flags=hikari.MessageFlag.EPHEMERAL)
+ await ctx.respond(
+ "❌ Blockbot can't find that role.", flags=hikari.MessageFlag.EPHEMERAL
+ )
return
raise exc