Made the plex functions use buttons

This commit is contained in:
NikolajDanger
2021-08-18 21:12:32 +02:00
parent ae71ff631d
commit 3819e56cd6
6 changed files with 305 additions and 307 deletions

View File

@ -34,6 +34,11 @@ class EventCog(commands.Cog):
"""Handle when someone reacts to a message.""" """Handle when someone reacts to a message."""
await self.bot.event_handler.on_reaction_add(reaction, user) await self.bot.event_handler.on_reaction_add(reaction, user)
@commands.Cog.listener()
async def on_component(self, ctx):
"""Handle when someone reacts to a message."""
await self.bot.event_handler.on_component(ctx)
def setup(bot): def setup(bot):
"""Add the eventcog to the bot.""" """Add the eventcog to the bot."""

View File

@ -1,11 +1,15 @@
"""Plex integration with the bot.""" """Plex integration with the bot."""
from math import floor, ceil from math import floor, ceil
import time import time
import json
import asyncio import asyncio
import requests import requests
import imdb import imdb
import discord import discord
import xmltodict
from discord_slash.utils.manage_components import (create_button,
create_actionrow)
from discord_slash.model import ButtonStyle
class Plex(): class Plex():
"""Container for Plex functions and commands.""" """Container for Plex functions and commands."""
@ -64,88 +68,102 @@ class Plex():
colour=0x00FF00 colour=0x00FF00
) )
message = await ctx.send(embed=embed) buttons = []
message_data = {"message_id":message.id,"imdb_ids":imdb_ids}
file_path = f"gwendolyn/resources/plex/old_message{ctx.channel.id}"
with open(file_path,"w") as file_pointer:
json.dump(message_data, file_pointer)
if len(movies) == 1: if len(movies) == 1:
await message.add_reaction("✔️") buttons.append(create_button(
style=ButtonStyle.green,
label="",
custom_id=f"plex:movie:{imdb_ids[0]}"
)
)
else: else:
for i in range(len(movies)): for i in range(len(movies)):
await message.add_reaction(["1","2","3","4","5"][i]) buttons.append(
create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=f"plex:movie:{imdb_ids[i]}"
)
)
buttons.append(create_button(
style=ButtonStyle.red,
label="X",
custom_id="plex:movie:"
)
)
action_rows = []
for i in range(((len(buttons)-1)//5)+1):
action_rows.append(
create_actionrow(
*buttons[(i*5):(min(len(buttons),i*5+5))]
)
)
await ctx.send(embed=embed, components=action_rows)
await message.add_reaction("")
message = await ctx.channel.fetch_message(message.id)
if (message.content != "" and
not isinstance(ctx.channel, discord.DMChannel)):
await message.clear_reactions()
async def add_movie(self, message, imdb_id, edit_message = True): async def add_movie(self, message, imdb_id, edit_message = True):
"""Add a movie to Plex server.""" """Add a movie to Plex server."""
if imdb_id is None:
if not edit_message:
await message.delete()
if imdb_id == "":
self.bot.log("Did not find what the user was searching for") self.bot.log("Did not find what the user was searching for")
if edit_message: message_text = "Try searching for the IMDB id"
await message.edit(
embed = None,
content = "Try searching for the IMDB id"
)
else:
await message.channel.send("Try searching for the IMDB id")
else: else:
self.bot.log("Trying to add movie "+str(imdb_id)) self.bot.log("Trying to add movie "+str(imdb_id))
# Searches for the movie using the imdb id through Radarr
api_key = self.credentials["radarr_key"] api_key = self.credentials["radarr_key"]
request_url = self.radarr_url+"movie/lookup/imdb?imdbId=tt"+imdb_id request_url = self.radarr_url+"movie/lookup/imdb?imdbId=tt"+imdb_id
request_url += "&apiKey="+api_key request_url += "&apiKey="+api_key
response = requests.get(request_url) response = requests.get(request_url)
# Makes the dict used for the post request
lookup_data = response.json() lookup_data = response.json()
post_data = {"qualityProfileId": 1, post_data = {
"rootFolder_path" : self.movie_path, "qualityProfileId": 1,
"monitored" : True, "rootFolderPath" : self.movie_path,
"addOptions": {"searchForMovie": True}} "monitored" : True,
"addOptions": {"searchForMovie": True}
}
for key in ["tmdbId","title","titleSlug","images","year"]: for key in ["tmdbId","title","titleSlug","images","year"]:
post_data.update({key : lookup_data[key]}) post_data.update({key : lookup_data[key]})
# Makes the post request
response = requests.post( response = requests.post(
url= self.radarr_url+"movie?apikey="+api_key, url = self.radarr_url+"movie?apikey="+api_key,
json = post_data json = post_data
) )
# Deciphers the response
if response.status_code == 201: if response.status_code == 201:
success_message = "{} successfully added to Plex".format( self.bot.log("Added "+post_data["title"]+" to Plex")
message_text = "{} successfully added to Plex".format(
post_data["title"] post_data["title"]
) )
if edit_message:
await message.edit(
embed = None,
content = success_message
)
else:
await message.channel.send(success_message)
self.bot.log("Added "+post_data["title"]+" to Plex")
elif response.status_code == 400: elif response.status_code == 400:
fail_text = self.long_strings["Already on Plex"].format( self.bot.log("The movie was already on plex")
message_text = self.long_strings["Already on Plex"].format(
post_data['title'] post_data['title']
) )
if edit_message:
await message.edit(embed = None, content = fail_text)
else:
await message.channel.send(fail_text)
else: else:
if edit_message:
await message.edit(
embed = None,
content = "Something went wrong"
)
else:
await message.channel.send("Something went wrong")
self.bot.log(str(response.status_code)+" "+response.reason) self.bot.log(str(response.status_code)+" "+response.reason)
message_text = "Something went wrong",
if edit_message:
await message.edit(
embed = None,
content = message_text,
components = []
)
else:
await message.channel.send(message_text)
async def request_show(self, ctx, show_name): async def request_show(self, ctx, show_name):
"""Request a show for the Plex server.""" """Request a show for the Plex server."""
@ -166,7 +184,7 @@ class Plex():
message_title = "**Is it any of these shows?**" message_title = "**Is it any of these shows?**"
message_text = "" message_text = ""
imdb_names = [] imdb_ids = []
for i, show in enumerate(shows): for i, show in enumerate(shows):
try: try:
@ -176,10 +194,10 @@ class Plex():
message_text += "\n"+str(i+1)+") "+show["title"] message_text += "\n"+str(i+1)+") "+show["title"]
except KeyError: except KeyError:
message_text += "Error" message_text += "Error"
imdb_names.append(show["title"]) imdb_ids.append(show.movieID)
self.bot.log( self.bot.log(
f"Returning a list of {len(shows)} possible shows: {imdb_names}" f"Returning a list of {len(shows)} possible shows: {imdb_ids}"
) )
embed = discord.Embed( embed = discord.Embed(
@ -188,42 +206,69 @@ class Plex():
colour=0x00FF00 colour=0x00FF00
) )
message = await ctx.send(embed=embed) buttons = []
message_data = {"message_id":message.id,"imdb_names":imdb_names}
file_path = "gwendolyn/resources/plex/old_message"+str(ctx.channel.id)
with open(file_path,"w") as file_pointer:
json.dump(message_data, file_pointer)
if len(shows) == 1: if len(shows) == 1:
await message.add_reaction("✔️") buttons.append(create_button(
else: style=ButtonStyle.green,
for i in range(len(shows)): label="",
await message.add_reaction(["1","2","3","4","5"][i]) custom_id=f"plex:show:{imdb_ids[0]}"
)
await message.add_reaction("")
message = await ctx.channel.fetch_message(message.id)
if message.content != "":
if not isinstance(ctx.channel, discord.DMChannel):
await message.clear_reactions()
async def add_show(self, message, imdb_name):
"""Add the requested show to Plex."""
if imdb_name is None:
self.bot.log("Did not find what the user was searching for")
await message.edit(
embed = None,
content = "Try searching for the IMDB id"
) )
else: else:
self.bot.log("Trying to add show "+str(imdb_name)) for i in range(len(shows)):
buttons.append(
create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=f"plex:show:{imdb_ids[i]}"
)
)
buttons.append(create_button(
style=ButtonStyle.red,
label="X",
custom_id="plex:show:"
)
)
action_rows = []
for i in range(((len(buttons)-1)//5)+1):
action_rows.append(
create_actionrow(
*buttons[(i*5):(min(len(buttons),i*5+5))]
)
)
await ctx.send(embed=embed, components=action_rows)
async def add_show(self, message, imdb_id, edit_message = True):
"""Add the requested show to Plex."""
if imdb_id == "":
self.bot.log("Did not find what the user was searching for")
message_text = "Try searching for the IMDB id"
else:
self.bot.log("Trying to add show "+str(imdb_id))
# Finds the tvdb id
tvdb_api_url = "https://thetvdb.com/api/"
tvdb_method = "GetSeriesByRemoteID.php"
tvdb_request_url = f"{tvdb_api_url}{tvdb_method}"
tvdb_id = xmltodict.parse(
requests.get(
tvdb_request_url+f"?imdbid=tt{imdb_id}",
headers = {"ContentType" : "application/json"}
).text
)['Data']['Series']['seriesid']
# Finds the rest of the information using Sonarr
api_key = self.credentials["sonarr_key"] api_key = self.credentials["sonarr_key"]
request_url = self.sonarr_url+"series/lookup?term=" request_url = self.sonarr_url+"series/lookup?term="
request_url += imdb_name.replace(" ","%20") request_url += f"tvdb:{tvdb_id}"
request_url += "&apiKey="+api_key request_url += "&apiKey="+api_key
response = requests.get(request_url) response = requests.get(request_url)
# Makes the dict used for the post request
lookup_data = response.json()[0] lookup_data = response.json()[0]
post_data = { post_data = {
"ProfileId" : 1, "ProfileId" : 1,
@ -234,29 +279,32 @@ class Plex():
for key in ["tvdbId","title","titleSlug","images","seasons"]: for key in ["tvdbId","title","titleSlug","images","seasons"]:
post_data.update({key : lookup_data[key]}) post_data.update({key : lookup_data[key]})
# Makes the post request
response = requests.post( response = requests.post(
url= self.sonarr_url+"series?apikey="+api_key, url= self.sonarr_url+"series?apikey="+api_key,
json = post_data json = post_data
) )
# Deciphers the response
if response.status_code == 201: if response.status_code == 201:
await message.edit(
embed = None,
content = post_data["title"]+" successfully added to Plex"
)
self.bot.log("Added a "+post_data["title"]+" to Plex") self.bot.log("Added a "+post_data["title"]+" to Plex")
message_text = post_data["title"]+" successfully added to Plex"
elif response.status_code == 400: elif response.status_code == 400:
text = self.long_strings["Already on Plex"].format( message_text = self.long_strings["Already on Plex"].format(
post_data['title'] post_data['title']
) )
await message.edit(embed = None, content = text)
else: else:
await message.edit(
embed = None,
content = "Something went wrong"
)
self.bot.log(str(response.status_code)+" "+response.reason) self.bot.log(str(response.status_code)+" "+response.reason)
message_text = "Something went wrong"
if edit_message:
await message.edit(
embed = None,
content = message_text,
components = []
)
else:
await message.channel.send(message_text)
async def __generate_download_list(self, show_dm, show_movies, show_shows, async def __generate_download_list(self, show_dm, show_movies, show_shows,
episodes): episodes):
@ -364,7 +412,9 @@ class Plex():
movie_list = requests.get( movie_list = requests.get(
self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"] self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"]
).json() ).json()
print(self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"]) print(
self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"]
)
movie_queue = requests.get( movie_queue = requests.get(
self.radarr_url+"queue?apiKey="+self.credentials["radarr_key"] self.radarr_url+"queue?apiKey="+self.credentials["radarr_key"]
).json() ).json()

View File

@ -1,135 +1,135 @@
""" """
Contains the Gwendolyn class, a subclass of the discord command bot. Contains the Gwendolyn class, a subclass of the discord command bot.
*Classes* *Classes*
--------- ---------
Gwendolyn(discord.ext.commands.Bot) Gwendolyn(discord.ext.commands.Bot)
""" """
import os # Used for loading cogs in Gwendolyn.addCogs import os # Used for loading cogs in Gwendolyn.addCogs
import finnhub # Used to add a finhub client to the bot import finnhub # Used to add a finhub client to the bot
import discord # Used for discord.Intents and discord.Status import discord # Used for discord.Intents and discord.Status
import discord_slash # Used to initialized SlashCommands object import discord_slash # Used to initialized SlashCommands object
import git # Used to pull when stopping import git # Used to pull when stopping
from discord.ext import commands # Used to inherit from commands.bot from discord.ext import commands # Used to inherit from commands.bot
from pymongo import MongoClient # Used for database management from pymongo import MongoClient # Used for database management
from gwendolyn.funcs import Money, StarWars, Games, Other, LookupFuncs from gwendolyn.funcs import Money, StarWars, Games, Other, LookupFuncs
from gwendolyn.utils import (get_options, get_credentials, log_this, from gwendolyn.utils import (get_options, get_credentials, log_this,
DatabaseFuncs, EventHandler, ErrorHandler, DatabaseFuncs, EventHandler, ErrorHandler,
long_strings) long_strings)
class Gwendolyn(commands.Bot): class Gwendolyn(commands.Bot):
""" """
A multifunctional Discord bot. A multifunctional Discord bot.
*Methods* *Methods*
--------- ---------
log(messages: Union[str, list], channel: str = "", log(messages: Union[str, list], channel: str = "",
level: int = 20) level: int = 20)
stop(ctx: discord_slash.context.SlashContext) stop(ctx: discord_slash.context.SlashContext)
defer(ctx: discord_slash.context.SlashContext) defer(ctx: discord_slash.context.SlashContext)
""" """
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
def __init__(self): def __init__(self):
"""Initialize the bot.""" """Initialize the bot."""
intents = discord.Intents.default() intents = discord.Intents.default()
intents.members = True intents.members = True
initiation_parameters = { initiation_parameters = {
"command_prefix": " ", "command_prefix": " ",
"case_insensitive": True, "case_insensitive": True,
"intents": intents, "intents": intents,
"status": discord.Status.dnd "status": discord.Status.dnd
} }
super().__init__(**initiation_parameters) super().__init__(**initiation_parameters)
self._add_clients_and_options() self._add_clients_and_options()
self._add_util_classes() self._add_util_classes()
self._add_function_containers() self._add_function_containers()
self._add_cogs() self._add_cogs()
def _add_clients_and_options(self): def _add_clients_and_options(self):
"""Add all the client, option and credentials objects.""" """Add all the client, option and credentials objects."""
self.long_strings = long_strings() self.long_strings = long_strings()
self.options = get_options() self.options = get_options()
self.credentials = get_credentials() self.credentials = get_credentials()
finnhub_key = self.credentials["finnhub_key"] finnhub_key = self.credentials["finnhub_key"]
self.finnhub_client = finnhub.Client(api_key=finnhub_key) self.finnhub_client = finnhub.Client(api_key=finnhub_key)
mongo_user = self.credentials["mongo_db_user"] mongo_user = self.credentials["mongo_db_user"]
mongo_password = self.credentials["mongo_db_password"] mongo_password = self.credentials["mongo_db_password"]
mongo_url = f"mongodb+srv://{mongo_user}:{mongo_password}@gwendolyn" mongo_url = f"mongodb+srv://{mongo_user}:{mongo_password}@gwendolyn"
mongo_url += ".qkwfy.mongodb.net/Gwendolyn?retryWrites=true&w=majority" mongo_url += ".qkwfy.mongodb.net/Gwendolyn?retryWrites=true&w=majority"
database_clint = MongoClient(mongo_url) database_clint = MongoClient(mongo_url)
if self.options["testing"]: if self.options["testing"]:
self.log("Testing mode") self.log("Testing mode")
self.database = database_clint["Gwendolyn-Test"] self.database = database_clint["Gwendolyn-Test"]
else: else:
self.database = database_clint["Gwendolyn"] self.database = database_clint["Gwendolyn"]
def _add_util_classes(self): def _add_util_classes(self):
"""Add all the classes used as utility.""" """Add all the classes used as utility."""
self.database_funcs = DatabaseFuncs(self) self.database_funcs = DatabaseFuncs(self)
self.event_handler = EventHandler(self) self.event_handler = EventHandler(self)
self.error_handler = ErrorHandler(self) self.error_handler = ErrorHandler(self)
slash_parameters = { slash_parameters = {
"sync_commands": True, "sync_commands": True,
"sync_on_cog_reload": True, "sync_on_cog_reload": True,
"override_type": True "override_type": True
} }
self.slash = discord_slash.SlashCommand(self, **slash_parameters) self.slash = discord_slash.SlashCommand(self, **slash_parameters)
def _add_function_containers(self): def _add_function_containers(self):
"""Add all the function containers used for commands.""" """Add all the function containers used for commands."""
self.star_wars = StarWars(self) self.star_wars = StarWars(self)
self.other = Other(self) self.other = Other(self)
self.lookup_funcs = LookupFuncs(self) self.lookup_funcs = LookupFuncs(self)
self.games = Games(self) self.games = Games(self)
self.money = Money(self) self.money = Money(self)
def _add_cogs(self): def _add_cogs(self):
"""Load cogs.""" """Load cogs."""
for filename in os.listdir("./gwendolyn/cogs"): for filename in os.listdir("./gwendolyn/cogs"):
if filename.endswith(".py"): if filename.endswith(".py"):
self.load_extension(f"gwendolyn.cogs.{filename[:-3]}") self.load_extension(f"gwendolyn.cogs.{filename[:-3]}")
def log(self, messages, channel: str = "", level: int = 20): def log(self, messages, channel: str = "", level: int = 20):
"""Log a message. Described in utils/util_functions.py.""" """Log a message. Described in utils/util_functions.py."""
log_this(messages, channel, level) log_this(messages, channel, level)
async def stop(self, ctx: discord_slash.context.SlashContext): async def stop(self, ctx: discord_slash.context.SlashContext):
""" """
Stop the bot, and stop running games. Stop the bot, and stop running games.
Only stops the bot if the user in ctx.author is one of the Only stops the bot if the user in ctx.author is one of the
admins given in options.txt. admins given in options.txt.
*parameters* *parameters*
------------ ------------
ctx: discord_slash.context.SlashContext ctx: discord_slash.context.SlashContext
The context of the "/stop" slash command. The context of the "/stop" slash command.
""" """
if f"#{ctx.author.id}" in self.options["admins"]: if f"#{ctx.author.id}" in self.options["admins"]:
await ctx.send("Pulling git repo and restarting...") await ctx.send("Pulling git repo and restarting...")
await self.change_presence(status=discord.Status.offline) await self.change_presence(status=discord.Status.offline)
self.database_funcs.wipe_games() self.database_funcs.wipe_games()
if not self.options["testing"]: if not self.options["testing"]:
git_client = git.cmd.Git("") git_client = git.cmd.Git("")
git_client.pull() git_client.pull()
self.log("Logging out", level=25) self.log("Logging out", level=25)
await self.close() await self.close()
else: else:
log_message = f"{ctx.author.display_name} tried to stop me!" log_message = f"{ctx.author.display_name} tried to stop me!"
self.log(log_message, str(ctx.channel_id)) self.log(log_message, str(ctx.channel_id))
await ctx.send(f"I don't think I will, {ctx.author.display_name}") await ctx.send(f"I don't think I will, {ctx.author.display_name}")
async def defer(self, ctx: discord_slash.context.SlashContext): async def defer(self, ctx: discord_slash.context.SlashContext):
"""Send a "Gwendolyn is thinking" message to the user.""" """Send a "Gwendolyn is thinking" message to the user."""
try: try:
await ctx.defer() await ctx.defer()
except discord_slash.error.AlreadyResponded: except discord_slash.error.AlreadyResponded:
self.log("defer failed") self.log("defer failed")

View File

@ -15,7 +15,7 @@ import discord # Used to init discord.Game and discord.Status, as well
from discord.ext import commands # Used to compare errors with command from discord.ext import commands # Used to compare errors with command
# errors # errors
from discord_slash.context import SlashContext from discord_slash.context import SlashContext, ComponentContext
from gwendolyn.utils.util_functions import emoji_to_command from gwendolyn.utils.util_functions import emoji_to_command
@ -72,13 +72,6 @@ class EventHandler():
channel = message.channel channel = message.channel
reacted_message = f"{user.display_name} reacted to a message" reacted_message = f"{user.display_name} reacted to a message"
self.bot.log(reacted_message, str(channel.id)) self.bot.log(reacted_message, str(channel.id))
plex_data = tests.plex_reaction_test(message)
# plex_data is a list containing 3 elements: whether it was
# the add_show/add_movie command message the reaction was to
# (bool), whether it's a movie (bool) (if false, it's a
# show), and the imdb ids/names for the for the movies or
# shows listed in the message (list).
reaction_test_parameters = [message, f"#{str(user.id)}"] reaction_test_parameters = [message, f"#{str(user.id)}"]
if tests.connect_four_reaction_test(*reaction_test_parameters): if tests.connect_four_reaction_test(*reaction_test_parameters):
@ -86,34 +79,6 @@ class EventHandler():
params = [message, f"#{user.id}", column-1] params = [message, f"#{user.id}", column-1]
await self.bot.games.connect_four.place_piece(*params) await self.bot.games.connect_four.place_piece(*params)
if plex_data[0]:
plex_functions = self.bot.other.plex
if plex_data[1]:
movie_pick = emoji_to_command(reaction.emoji)
if movie_pick == "none":
imdb_id = None
else:
imdb_id = plex_data[2][movie_pick-1]
if isinstance(channel, discord.DMChannel):
await message.delete()
await plex_functions.add_movie(message, imdb_id, False)
else:
await message.clear_reactions()
await plex_functions.add_movie(message, imdb_id)
else:
show_pick = emoji_to_command(reaction.emoji)
if show_pick == "none":
imdb_name = None
else:
imdb_name = plex_data[2][show_pick-1]
if isinstance(channel, discord.DMChannel):
await message.delete()
await plex_functions.add_show(message, imdb_name, False)
else:
await message.clear_reactions()
await plex_functions.add_show(message, imdb_name)
elif tests.hangman_reaction_test(*reaction_test_parameters): elif tests.hangman_reaction_test(*reaction_test_parameters):
self.bot.log("They reacted to the hangman message") self.bot.log("They reacted to the hangman message")
@ -126,6 +91,25 @@ class EventHandler():
else: else:
self.bot.log("Bot they didn't react with a valid guess") self.bot.log("Bot they didn't react with a valid guess")
async def on_component(self, ctx: ComponentContext):
info = ctx.custom_id.split(":")
channel = ctx.origin_message.channel
if info[0] == "plex":
if info[1] == "movie":
await self.bot.other.plex.add_movie(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
if info[1] == "show":
await self.bot.other.plex.add_show(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
class ErrorHandler(): class ErrorHandler():
""" """

View File

@ -6,7 +6,6 @@ Contains classes used for utilities.
DatabaseFuncs() DatabaseFuncs()
""" """
import os # Used to test if files exist import os # Used to test if files exist
import json # Used to read the data about add_movie/add_show
import time # Used to test how long it's been since commands were synced import time # Used to test how long it's been since commands were synced
import re # Used in get_id import re # Used in get_id
@ -206,45 +205,6 @@ class DatabaseFuncs():
return game_message return game_message
def plex_reaction_test(self, message: discord.Message):
"""
Test if the given message is the response to a plex request.
*Parameters*
------------
message: discord.Message
The message to test.
*Returns*
---------
: bool
Whether the message is the response to a plex request.
: bool
Whether it was a movie request (false for a show
request)
: list
A list of ids or names of the shows or movies that
Gwendolyn presented after the request.
"""
channel = message.channel
old_messages_path = "gwendolyn/resources/plex/"
file_path = old_messages_path + f"old_message{str(channel.id)}"
if os.path.isfile(file_path):
with open(file_path, "r") as file_pointer:
data = json.load(file_pointer)
else:
return (False, None, None)
if data["message_id"] != message.id:
return (False, None, None)
if "imdb_ids" in data:
return_data = (True, True, data["imdb_ids"])
else:
return_data = (True, False, data["imdb_names"])
return return_data
async def imdb_commands(self): async def imdb_commands(self):
"""Sync the slash commands with the discord API.""" """Sync the slash commands with the discord API."""
collection = self.bot.database["last synced"] collection = self.bot.database["last synced"]

View File

@ -23,7 +23,6 @@ lxml==4.6.3
more-itertools==8.8.0 more-itertools==8.8.0
multidict==5.1.0 multidict==5.1.0
Pillow==8.3.1 Pillow==8.3.1
pip==21.2.3
pymongo==3.12.0 pymongo==3.12.0
requests==2.26.0 requests==2.26.0
setuptools==57.4.0 setuptools==57.4.0