From 2060e25f752400d1e2928131d194600b139ee617 Mon Sep 17 00:00:00 2001
From: ErrorNoInternet <errornointernet@envs.net>
Date: Mon, 30 Dec 2024 03:31:49 -0500
Subject: [PATCH] refactor(tools): clean up and use proper argument parser

---
 commands/__init__.py |  2 +-
 commands/tools.py    | 64 ++++++++++++++++++++++++++++++++++++++++----
 commands/voice.py    |  6 ++++-
 constants.py         |  5 ++--
 events.py            |  2 +-
 main.py              |  4 +--
 utils.py             |  2 +-
 ytdlp.py             |  6 ++---
 8 files changed, 75 insertions(+), 16 deletions(-)

diff --git a/commands/__init__.py b/commands/__init__.py
index 0ef2829..7e74ea2 100644
--- a/commands/__init__.py
+++ b/commands/__init__.py
@@ -9,7 +9,7 @@ from .utils import *
 
 def __reload_module__():
     for name, module in globals().items():
-        if inspect.ismodule(module):
+        if inspect.ismodule(module) and name not in constants.RELOAD_BLACKLISTED_MODULES:
             importlib.reload(module)
             if "__reload_module__" in dir(module) and name not in reloaded_modules:
                 reloaded_modules.add(name)
diff --git a/commands/tools.py b/commands/tools.py
index 8df4aaf..c6cb325 100644
--- a/commands/tools.py
+++ b/commands/tools.py
@@ -1,23 +1,77 @@
+import importlib
+import inspect
 import re
 
+import arguments
 import commands
+import constants
+from state import reloaded_modules
 
 
 async def clear(message):
-    tokens = commands.tokenize(message.content)[1:]
-    if len(tokens) < 2:
-        await message.reply("no count and/or regex supplied!", mention_author=False)
+    tokens = commands.tokenize(message.content)
+    parser = arguments.ArgumentParser(
+        tokens[0],
+        "bulk delete messages in the current channel matching certain criteria",
+    )
+    parser.add_argument(
+        "count",
+        type=int,
+        choices=range(1, 1001),
+        metavar="[1-1000]",
+        help="amount of messages to delete",
+    )
+    parser.add_argument(
+        "-r",
+        "--regex",
+        required=False,
+        help="delete messages with content matching this regex",
+    )
+    parser.add_argument(
+        "-i",
+        "--author-id",
+        type=int,
+        action="append",
+        help="delete messages whose author matches this id",
+    )
+    parser.add_argument(
+        "-o",
+        "--oldest-first",
+        action="store_true",
+        help="delete oldest messages first",
+    )
+    if not (args := await parser.parse_args(message, tokens)):
         return
 
+    def check(m):
+        c = []
+        if r := args.regex:
+            c.append(re.match(r, m.content))
+        if i := args.author_id:
+            c.append(m.author.id in i)
+        return all(c)
+
     message_count = len(
         await message.channel.purge(
-            limit=int(tokens[0]), check=lambda m: re.match(tokens[1], m.content)
+            limit=args.count, check=check, oldest_first=args.oldest_first
         )
     )
     try:
         await message.reply(
-            f"successfully purged **{message_count} {'message' if message_count == 1 else 'messages'}**",
+            f"purged **{message_count} {'message' if message_count == 1 else 'messages'}**",
             mention_author=False,
         )
     except:
         pass
+
+
+def __reload_module__():
+    for name, module in globals().items():
+        if (
+            inspect.ismodule(module)
+            and name not in constants.RELOAD_BLACKLISTED_MODULES
+        ):
+            importlib.reload(module)
+            if "__reload_module__" in dir(module) and name not in reloaded_modules:
+                reloaded_modules.add(name)
+                module.__reload_module__()
diff --git a/commands/voice.py b/commands/voice.py
index 546719a..902239d 100644
--- a/commands/voice.py
+++ b/commands/voice.py
@@ -3,6 +3,7 @@ import inspect
 
 import arguments
 import commands
+import constants
 import utils
 import ytdlp
 from state import client, playback_queue, reloaded_modules
@@ -227,7 +228,10 @@ def generate_queue_list(queue: list):
 
 def __reload_module__():
     for name, module in globals().items():
-        if inspect.ismodule(module):
+        if (
+            inspect.ismodule(module)
+            and name not in constants.RELOAD_BLACKLISTED_MODULES
+        ):
             importlib.reload(module)
             if "__reload_module__" in dir(module) and name not in reloaded_modules:
                 reloaded_modules.add(name)
diff --git a/constants.py b/constants.py
index 49c30c0..0d3d4d8 100644
--- a/constants.py
+++ b/constants.py
@@ -3,8 +3,9 @@ import os
 EMBED_COLOR = 0xFF6600
 OWNERS = [531392146767347712]
 PREFIX = "%"
+RELOAD_BLACKLISTED_MODULES = ["re", "argparse"]
 
-ytdl_format_options = {
+YTDL_OPTIONS = {
     "default_search": "auto",
     "format": "bestaudio/best",
     "ignoreerrors": False,
@@ -19,6 +20,6 @@ ytdl_format_options = {
 }
 
 
-secrets = {
+SECRETS = {
     "TOKEN": os.getenv("BOT_TOKEN"),
 }
diff --git a/events.py b/events.py
index 26c35f3..06623cf 100644
--- a/events.py
+++ b/events.py
@@ -100,7 +100,7 @@ async def on_message(message):
 
 def __reload_module__():
     for name, module in globals().items():
-        if inspect.ismodule(module):
+        if inspect.ismodule(module) and name not in constants.RELOAD_BLACKLISTED_MODULES:
             importlib.reload(module)
             if "__reload_module__" in dir(module) and name not in reloaded_modules:
                 reloaded_modules.add(name)
diff --git a/main.py b/main.py
index ffb1850..167f1af 100644
--- a/main.py
+++ b/main.py
@@ -36,7 +36,7 @@ async def on_message(message):
         commands.Command.RELOAD
     ]:
         for name, module in globals().items():
-            if inspect.ismodule(module):
+            if inspect.ismodule(module) and name not in constants.RELOAD_BLACKLISTED_MODULES:
                 importlib.reload(module)
                 if "__reload_module__" in dir(module) and name not in reloaded_modules:
                     reloaded_modules.add(name)
@@ -48,4 +48,4 @@ async def on_message(message):
     await events.on_message(message)
 
 
-client.run(constants.secrets["TOKEN"])
+client.run(constants.SECRETS["TOKEN"])
diff --git a/utils.py b/utils.py
index 3b5e2e9..cd6a78a 100644
--- a/utils.py
+++ b/utils.py
@@ -14,7 +14,7 @@ async def invalid_user_handler(interaction):
 
 
 def filter_secrets(text: str) -> str:
-    for secret_name, secret in constants.secrets.items():
+    for secret_name, secret in constants.SECRETS.items():
         if not secret:
             continue
         text = text.replace(secret, f"<{secret_name}>")
diff --git a/ytdlp.py b/ytdlp.py
index 2733e5e..65299d4 100644
--- a/ytdlp.py
+++ b/ytdlp.py
@@ -9,7 +9,7 @@ import yt_dlp
 import constants
 from state import reloaded_modules
 
-ytdl = yt_dlp.YoutubeDL(constants.ytdl_format_options)
+ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)
 
 
 class YTDLSource(disnake.PCMVolumeTransformer):
@@ -45,11 +45,11 @@ class YTDLSource(disnake.PCMVolumeTransformer):
 
 def __reload_module__():
     for name, module in globals().items():
-        if inspect.ismodule(module):
+        if inspect.ismodule(module) and name not in constants.RELOAD_BLACKLISTED_MODULES:
             importlib.reload(module)
             if "__reload_module__" in dir(module) and name not in reloaded_modules:
                 reloaded_modules.add(name)
                 module.__reload_module__()
 
     global ytdl
-    ytdl = yt_dlp.YoutubeDL(constants.ytdl_format_options)
+    ytdl = yt_dlp.YoutubeDL(constants.YTDL_OPTIONS)