Skip to content

Commit 0d6f27e

Browse files
committed
Convert bot to discord.py 2.0
TODO: Reject commands if the bot is not fully started up
1 parent b323049 commit 0d6f27e

File tree

14 files changed

+540
-533
lines changed

14 files changed

+540
-533
lines changed

launcher.py

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import asyncio
22
import atexit
33
import glob
4-
import sys
5-
6-
from time import sleep
4+
from http.client import HTTPException
75

6+
import discord
87
import numpy as np
98
import requests
9+
from discord import Embed, NotFound, Interaction
10+
from discord.app_commands import CommandOnCooldown, MissingPermissions, BotMissingPermissions
1011

11-
from lib.bot import Bot
12+
from lib.bot import Bot, IGNORE_EXCEPTIONS
1213
from lib.config import Config
1314
from lib.progress import Progress
14-
from asyncer import asyncify
1515

1616
COGS = [path.split("\\")[-1][:-3] if "\\" in path else path.split("/")[-1][:-3] for path in
1717
glob.glob('./lib/cogs/*.py')]
@@ -24,16 +24,62 @@
2424
SHARDS_SPLIT: list[np.ndarray[int]] = np.array_split(SHARDS_LIST, CLUSTERS)
2525

2626

27-
def start(cluster_id: int):
28-
bot: Bot = Bot(list((SHARDS_SPLIT[cluster_id])), VERSION)
27+
async def start():
28+
bot = Bot(SHARDS_LIST, VERSION)
2929
progress = Progress("Registering Cogs", len(COGS))
3030
for index, cog in enumerate(COGS):
31-
bot.load_extension(f"lib.cogs.{cog}")
32-
# sleep(.2)
31+
await bot.load_extension(f"lib.cogs.{cog}")
3332
progress.next()
34-
atexit.register(bot.db.commit)
35-
bot.run(bot.config.token)
33+
34+
# @bot.event
35+
# async def on_interaction(ctx: Interaction):
36+
# if isinstance(ctx.command, Command):
37+
# print('is Command')
38+
# raise BotNotReady()
39+
40+
@bot.tree.error
41+
async def on_command_error(ctx: Interaction, exc) -> None:
42+
if any([isinstance(exc, error) for error in IGNORE_EXCEPTIONS]):
43+
pass
44+
elif isinstance(exc, CommandOnCooldown):
45+
embed: Embed = Embed(title='Command on Cooldown',
46+
description=f"That command is on cooldown. Try again in {exc.retry_after:,.2f} seconds.",
47+
colour=0xff0000)
48+
await bot.send(ctx, embed=embed)
49+
elif isinstance(exc, MissingPermissions):
50+
embed: Embed = Embed(title='You are missing permissions', description=f'>>> {exc}', colour=0xff0000)
51+
await bot.send(ctx, embed=embed)
52+
elif isinstance(exc, BotMissingPermissions):
53+
embed: Embed = Embed(title='Bot Missing Permissions', description=f">>> {exc}", colour=0xff0000)
54+
await bot.send(ctx, embed=embed)
55+
elif isinstance(exc, HTTPException):
56+
embed: Embed = Embed(title="Http Error", description='Message failed to send', colour=0xff0000)
57+
await bot.send(ctx, embed=embed)
58+
elif isinstance(exc, NotFound):
59+
await bot.send(ctx,
60+
embed=Embed(title='Not Found Error', description='One or more items could not be found.',
61+
colour=0xff0000))
62+
elif hasattr(exc, "original"):
63+
if isinstance(exc.original, HTTPException):
64+
embed: Embed = Embed(title="Http Error", description='Message failed to send', colour=0xff0000)
65+
await bot.send(ctx, embed=embed)
66+
if isinstance(exc.original, discord.Forbidden):
67+
embed: Embed = Embed(title='Forbidden Error', description='Insufficient Permissions',
68+
colour=0xff0000)
69+
await bot.send(ctx, embed=embed)
70+
else:
71+
raise exc.original
72+
73+
else:
74+
raise exc
75+
76+
async def exit_handler():
77+
bot.db.commit()
78+
await bot.close()
79+
80+
atexit.register(exit_handler)
81+
await bot.start(bot.config.token)
3682

3783

3884
if __name__ == '__main__':
39-
start(0)
85+
asyncio.run(start())

lib/bot/__init__.py

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,34 @@
33
import os
44
from datetime import datetime
55
from http.client import HTTPException
6+
import random
67
from typing import Any
78

89
import discord
910
import psutil
1011
import tzlocal
1112
from apscheduler.schedulers.asyncio import AsyncIOScheduler
12-
from discord import Interaction, Guild
13+
from discord import Guild, app_commands, Interaction, VoiceChannel, TextChannel, Message
14+
from discord.app_commands import errors, Command
1315
from discord.embeds import Embed
1416
from discord.errors import NotFound
15-
from discord.ext.commands import AutoShardedBot as BaseBot
17+
from discord.ext.commands import AutoShardedBot, Context
18+
from discord import AutoShardedClient
19+
from discord.ext.commands._types import BotT
1620
from discord.ext.commands.errors import CommandNotFound, BadArgument, MissingRequiredArgument, CommandOnCooldown, \
1721
MissingPermissions, BotMissingPermissions
1822

1923
from lib.config import Config
20-
from lib.context import CustomContext
2124
from lib.db import DB
22-
from lib.progress import Progress
25+
from lib.errors import BotNotReady
26+
from lib.progress import Progress, Timer
2327
from lib.urban import UrbanDictionary
2428

2529
COMMAND_ERROR_REGEX = r"Command raised an exception: (.*?(?=: )): (.*)"
2630
IGNORE_EXCEPTIONS = (CommandNotFound, BadArgument, RuntimeError)
2731

2832

29-
class Bot(BaseBot):
33+
class Bot(AutoShardedBot):
3034
def __init__(self, shards: list[int], version: str):
3135
self.config: Config = Config()
3236
self.db: DB = DB()
@@ -36,24 +40,26 @@ def __init__(self, shards: list[int], version: str):
3640
self.shards_ready = False
3741
self.ready = False
3842
self.expected_shards = len(shards)
43+
self.timer = Timer()
3944
self.shard_progress = Progress('Shards Ready', self.expected_shards)
4045
self.urban: UrbanDictionary = UrbanDictionary()
4146
self.VERSION = version
4247
super().__init__(
48+
command_prefix=None,
4349
owner_id="507214515641778187",
4450
shards=shards,
4551
intents=discord.Intents.all(),
46-
debug_guilds=["1064582321728143421"],
4752
description="Misc Bot used for advanced moderation and guild customization")
4853
self.tasks.add_job(self.db.commit, trigger='interval', minutes=30)
4954
self.shard_progress.start()
5055

5156
async def on_connect(self):
52-
await self.sync_commands()
57+
await self.tree.sync()
5358
while not self.shards_ready:
5459
await asyncio.sleep(.5)
55-
print(f"Signed into {self.user.display_name}#{self.user.discriminator}")
5660
self.register_guilds()
61+
print(f"Signed into {self.user.display_name}#{self.user.discriminator}")
62+
# asyncio.ensure_future(self.timer.start())
5763

5864
async def on_shard_ready(self, shard_id):
5965
await self.change_presence(activity=discord.Activity(type=discord.ActivityType.watching,
@@ -63,6 +69,34 @@ async def on_shard_ready(self, shard_id):
6369
if shard_id + 1 == self.expected_shards:
6470
self.shards_ready = True
6571

72+
async def on_interaction(self, ctx: Interaction):
73+
if isinstance(ctx.command, Command):
74+
name_list, options = self.get_name(ctx.data, [])
75+
name = " ".join(name_list)
76+
self.db.execute(f"""INSERT INTO commands VALUES (?,?,?,?,?)""", name, ctx.guild_id,
77+
ctx.user.id, json.dumps(options), datetime.now().timestamp())
78+
79+
@staticmethod
80+
async def send(ctx: Interaction, *args, **kwargs):
81+
if kwargs.get('embed'):
82+
embed: Embed = kwargs['embed']
83+
if not isinstance(embed.colour, discord.Colour):
84+
color = int("0x" + ''.join([random.choice('0123456789ABCDEF') for j in range(6)]), 16)
85+
embed.colour = color
86+
embed.set_footer(text="Made by Gccody")
87+
embed.timestamp = datetime.now()
88+
# embed.set_thumbnail(url=self.logo_path)
89+
kwargs['embed'] = embed
90+
if ctx.is_expired():
91+
channel = ctx.channel
92+
if not isinstance(channel, VoiceChannel):
93+
return await ctx.channel.send(*args, **kwargs)
94+
try:
95+
await ctx.original_response()
96+
return await ctx.followup.send(*args, **kwargs)
97+
except NotFound:
98+
return await ctx.response.send_message(*args, **kwargs)
99+
66100
def register_guilds(self):
67101
progress = Progress('Registering guilds', len(self.guilds))
68102
for guild in self.guilds:
@@ -71,12 +105,6 @@ def register_guilds(self):
71105
self.db.commit()
72106
self.ready = True
73107
self.tasks.start()
74-
print('\nEverything is ready!')
75-
76-
async def get_application_context(
77-
self, interaction: Interaction, cls=CustomContext
78-
):
79-
return await super().get_application_context(interaction, cls=cls)
80108

81109
async def on_guild_join(self, guild: Guild):
82110
self.db.execute("""INSERT OR IGNORE INTO guilds VALUES (?,?,?)""", guild.id, None, None)
@@ -105,50 +133,6 @@ def get_name(self, data: Any, groups: list[str]):
105133
else:
106134
return self.get_name(data.get('options'), [*groups, data.get('name')])
107135

108-
async def on_interaction(self, interaction: discord.Interaction):
109-
if not self.ready: return
110-
if interaction.is_command():
111-
name_list, options = self.get_name(interaction.data, [])
112-
name = " ".join(name_list)
113-
self.db.execute(f"""INSERT INTO commands VALUES (?,?,?,?,?)""", name, interaction.guild_id,
114-
interaction.user.id, json.dumps(options), datetime.now().timestamp())
115-
return await super().on_interaction(interaction=interaction)
116-
117-
async def on_application_command_error(self, ctx: CustomContext, exc) -> None:
118-
if any([isinstance(exc, error) for error in IGNORE_EXCEPTIONS]):
119-
pass
120-
elif isinstance(exc, MissingRequiredArgument):
121-
await ctx.respond("One or more required arguments are missing.")
122-
elif isinstance(exc, CommandOnCooldown):
123-
embed: Embed = Embed(title='Command on Cooldown',
124-
description=f"That command is on cooldown. Try again in {exc.retry_after:,.2f} seconds.",
125-
colour=0xff0000)
126-
await ctx.respond(embed=embed)
127-
elif isinstance(exc, MissingPermissions):
128-
embed: Embed = Embed(title='You are missing permissions', description=f'>>> {exc}', colour=0xff0000)
129-
elif isinstance(exc, BotMissingPermissions):
130-
embed: Embed = Embed(title='Bot Missing Permissions', description=f">>> {exc}", colour=0xff0000)
131-
await ctx.respond(embed=embed)
132-
elif isinstance(exc, HTTPException):
133-
embed: Embed = Embed(title="Http Error", description='Message failed to send', colour=0xff0000)
134-
await ctx.respond(embed=embed)
135-
elif isinstance(exc, NotFound):
136-
await ctx.respond(embed=Embed(title='Not Found Error', description='One or more items could not be found.',
137-
colour=0xff0000))
138-
elif hasattr(exc, "original"):
139-
if isinstance(exc.original, HTTPException):
140-
embed: Embed = Embed(title="Http Error", description='Message failed to send', colour=0xff0000)
141-
await ctx.respond(embed=embed)
142-
if isinstance(exc.original, discord.Forbidden):
143-
await ctx.message.delete()
144-
embed: Embed = Embed(title='Forbidden Error', description='Insufficient Permissions', colour=0xff0000)
145-
await ctx.respond(embed=embed)
146-
else:
147-
raise exc.original
148-
149-
else:
150-
raise exc
151-
152136
@staticmethod
153137
async def cpu_percent(interval=None, *args, **kwargs):
154138
python_process = psutil.Process(os.getpid())
Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,50 @@
1+
from typing import Optional
2+
13
import discord
2-
from discord.ext.commands import Cog, has_guild_permissions, bot_has_guild_permissions
3-
from discord.commands import SlashCommandGroup, option
4+
from discord import app_commands, Interaction
45
from discord.channel import TextChannel
56
from discord.embeds import Embed
7+
from discord.ext.commands import Cog, has_guild_permissions, bot_has_guild_permissions
68

79
from lib.bot import Bot
8-
from lib.context import CustomContext
910

1011

1112
class Announce(Cog):
13+
announce = app_commands.Group(name='announcements', description='Enable and disable announcements')
14+
1215
def __init__(self, bot):
1316
self.bot: Bot = bot
1417

15-
announce = SlashCommandGroup('announcements')
16-
1718
@staticmethod
1819
def get_news(channels: list[TextChannel]) -> TextChannel | None:
1920
for ch in channels:
2021
if ch.is_news():
2122
return ch
2223

2324
@announce.command(name="enable", description='Enable bot announcements')
24-
@option(name='channel',
25-
type=discord.TextChannel,
26-
description='Bot Announcements Channel',
27-
required=False)
25+
@app_commands.describe(channel='Bot Announcements Channel')
2826
@has_guild_permissions(manage_guild=True)
2927
@bot_has_guild_permissions(send_messages=True)
30-
async def announce_enable(self, ctx: CustomContext, channel: discord.TextChannel | None):
28+
async def announce_enable(self, ctx: Interaction, channel: Optional[discord.TextChannel]):
3129
channel = channel if channel is not None else self.get_news(ctx.guild.text_channels)
3230
if channel is None:
33-
return await ctx.respond(Embed(title='Channel Not Found', description=f">>> Can't find an announcements channel to enable", colour=0xff0000))
31+
return await ctx.response.send_message(
32+
Embed(title=f">>> Can't find an announcements channel to enable", colour=0xff0000))
3433
if not channel.permissions_for(await ctx.guild.fetch_member(self.bot.user.id)).send_messages:
35-
return await ctx.respond(Embed(title='Missing Permissions', description=f">>> I can't send messages in channel: {channel.name} ({channel.id})"))
34+
return await ctx.response.send_message(
35+
Embed(title=f">>> I can't send messages in channel: {channel.name} ({channel.id})", colour=0xff0000))
3636
self.bot.db.execute("""UPDATE guilds SET a_id=? WHERE id=?""", channel.id, ctx.guild.id)
37-
await ctx.respond(embed=Embed(title='Update Announcments', description=f">>> Successfully Enabled Announcments in {channel.mention} ({channel.id})", colour=0x00ff00))
37+
print('here at send')
38+
await self.bot.send(ctx, embed=Embed(
39+
title=f">>> Successfully Enabled Announcements in {channel.mention} ({channel.id})"))
3840

3941
@announce.command(name='disable', description='Disable bot announcements')
4042
@has_guild_permissions(manage_guild=True)
41-
async def announce_disable(self, ctx: CustomContext):
43+
async def announce_disable(self, ctx: Interaction):
4244
self.bot.db.execute("""UPDATE guilds SET a_id=?""")
45+
await self.bot.send(ctx,
46+
embed=Embed(title=f">>> Successfully Disabled Announcements"))
4347

4448

45-
def setup(bot):
46-
bot.add_cog(Announce(bot))
49+
async def setup(bot):
50+
await bot.add_cog(Announce(bot))

0 commit comments

Comments
 (0)