🔀 Merging with master
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@ -153,11 +153,11 @@ static
|
||||
token.txt
|
||||
credentials.txt
|
||||
options.txt
|
||||
resources/starWars/destinyPoints.txt
|
||||
resources/star_wars/destinyPoints.txt
|
||||
resources/bedreNetflix/
|
||||
resources/games/hilo/
|
||||
resources/games/blackjackTables/
|
||||
resources/games/oldImages/
|
||||
resources/games/old_images/
|
||||
resources/games/connect4Boards/
|
||||
resources/games/hexBoards/
|
||||
resources/games/hangmanBoards/
|
||||
|
137
Gwendolyn.py
137
Gwendolyn.py
@ -1,63 +1,138 @@
|
||||
import os, finnhub, platform, asyncio, discord
|
||||
"""
|
||||
Contains the Gwendolyn class, and runs it when run as script.
|
||||
|
||||
from discord.ext import commands
|
||||
from discord_slash import SlashCommand
|
||||
from pymongo import MongoClient
|
||||
*Classes*
|
||||
---------
|
||||
Gwendolyn(discord.ext.commands.Bot)
|
||||
"""
|
||||
import os # Used for loading cogs in Gwendolyn.addCogs
|
||||
import finnhub # Used to add a finhub client to the bot
|
||||
import platform # Used to test if the bot is running on windows, in
|
||||
# order to fix a bug with asyncio
|
||||
import asyncio # used to set change the loop policy if the bot is
|
||||
# running on windows
|
||||
import discord # Used for discord.Intents and discord.Status
|
||||
import discord_slash # Used to initialized SlashCommands object
|
||||
|
||||
from discord.ext import commands # Used to inherit from commands.bot
|
||||
from pymongo import MongoClient # Used for database management
|
||||
from funcs import Money, StarWars, Games, Other, LookupFuncs
|
||||
from utils import Options, Credentials, logThis, makeFiles, databaseFuncs, EventHandler, ErrorHandler
|
||||
from utils import (Options, Credentials, logThis, makeFiles, databaseFuncs,
|
||||
EventHandler, ErrorHandler, longStrings)
|
||||
|
||||
|
||||
class Gwendolyn(commands.Bot):
|
||||
"""
|
||||
A multifunctional Discord bot.
|
||||
|
||||
*Methods*
|
||||
---------
|
||||
log(messages: Union[str, list], channel: str = "",
|
||||
level: int = 20)
|
||||
stop(ctx: discord_slash.context.SlashContext)
|
||||
defer(ctx: discord_slash.context.SlashContext)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the bot."""
|
||||
intents = discord.Intents.default()
|
||||
intents.members = True
|
||||
initParams = {
|
||||
"command_prefix": " ",
|
||||
"case_insensitive": True,
|
||||
"intents": intents,
|
||||
"status": discord.Status.dnd
|
||||
}
|
||||
super().__init__(**initParams)
|
||||
|
||||
self._addClientsAndOptions()
|
||||
self._addUtilClasses()
|
||||
self._addFunctionContainers()
|
||||
self._addCogs()
|
||||
|
||||
def _addClientsAndOptions(self):
|
||||
"""Add all the client, option and credentials objects."""
|
||||
self.longStrings = longStrings()
|
||||
self.options = Options()
|
||||
self.credentials = Credentials()
|
||||
self.finnhubClient = finnhub.Client(api_key = self.credentials.finnhubKey)
|
||||
self.MongoClient = MongoClient(f"mongodb+srv://{self.credentials.mongoDBUser}:{self.credentials.mongoDBPassword}@gwendolyn.qkwfy.mongodb.net/Gwendolyn?retryWrites=true&w=majority")
|
||||
finnhubKey = self.credentials.finnhubKey
|
||||
self.finnhubClient = finnhub.Client(api_key=finnhubKey)
|
||||
mongoUser = self.credentials.mongoDBUser
|
||||
mongoPassword = self.credentials.mongoDBPassword
|
||||
mongoLink = f"mongodb+srv://{mongoUser}:{mongoPassword}@gwendolyn"
|
||||
mongoLink += ".qkwfy.mongodb.net/Gwendolyn?retryWrites=true&w=majority"
|
||||
dataBaseClient = MongoClient(mongoLink)
|
||||
|
||||
if self.options.testing:
|
||||
self.log("Testing mode")
|
||||
self.database = self.MongoClient["Gwendolyn-Test"]
|
||||
self.database = dataBaseClient["Gwendolyn-Test"]
|
||||
else:
|
||||
self.database = self.MongoClient["Gwendolyn"]
|
||||
self.database = dataBaseClient["Gwendolyn"]
|
||||
|
||||
def _addUtilClasses(self):
|
||||
"""Add all the classes used as utility."""
|
||||
self.databaseFuncs = databaseFuncs(self)
|
||||
self.eventHandler = EventHandler(self)
|
||||
self.errorHandler = ErrorHandler(self)
|
||||
slashParams = {
|
||||
"sync_commands": True,
|
||||
"sync_on_cog_reload": True,
|
||||
"override_type": True
|
||||
}
|
||||
self.slash = discord_slash.SlashCommand(self, **slashParams)
|
||||
|
||||
def _addFunctionContainers(self):
|
||||
"""Add all the function containers used for commands."""
|
||||
self.starWars = StarWars(self)
|
||||
self.other = Other(self)
|
||||
self.lookupFuncs = LookupFuncs(self)
|
||||
self.games = Games(self)
|
||||
self.money = Money(self)
|
||||
self.databaseFuncs = databaseFuncs(self)
|
||||
self.eventHandler = EventHandler(self)
|
||||
self.errorHandler = ErrorHandler(self)
|
||||
|
||||
intents = discord.Intents.default()
|
||||
intents.members = True
|
||||
def _addCogs(self):
|
||||
"""Load cogs."""
|
||||
for filename in os.listdir("./cogs"):
|
||||
if filename.endswith(".py"):
|
||||
self.load_extension(f"cogs.{filename[:-3]}")
|
||||
|
||||
super().__init__(command_prefix=" ", case_insensitive=True, intents = intents, status = discord.Status.dnd)
|
||||
|
||||
def log(self, messages, channel : str = "", level : int = 20):
|
||||
def log(self, messages, channel: str = "", level: int = 20):
|
||||
"""Log a message. Described in utils/utilFunctions.py."""
|
||||
logThis(messages, channel, level)
|
||||
|
||||
async def stop(self, ctx):
|
||||
async def stop(self, ctx: discord_slash.context.SlashContext):
|
||||
"""
|
||||
Stop the bot, and stop running games.
|
||||
|
||||
Only stops the bot if the user in ctx.author is one of the
|
||||
admins given in options.txt.
|
||||
|
||||
*parameters*
|
||||
------------
|
||||
ctx: discord_slash.context.SlashContext
|
||||
The context of the "/stop" slash command.
|
||||
"""
|
||||
if f"#{ctx.author.id}" in self.options.admins:
|
||||
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.databaseFuncs.stopServer()
|
||||
self.databaseFuncs.wipeGames()
|
||||
|
||||
self.log("Logging out", level = 25)
|
||||
self.log("Logging out", level=25)
|
||||
await self.close()
|
||||
else:
|
||||
self.log(f"{ctx.author.display_name} tried to stop me! (error code 201)",str(ctx.channel_id))
|
||||
await ctx.send(f"I don't think I will, {ctx.author.display_name} (error code 201)")
|
||||
logMessage = f"{ctx.author.display_name} tried to stop me!"
|
||||
self.log(logMessage, str(ctx.channel_id))
|
||||
await ctx.send(f"I don't think I will, {ctx.author.display_name}")
|
||||
|
||||
async def defer(self, ctx):
|
||||
async def defer(self, ctx: discord_slash.context.SlashContext):
|
||||
"""Send a "Gwendolyn is thinking" message to the user."""
|
||||
try:
|
||||
await ctx.defer()
|
||||
except:
|
||||
except discord_slash.error.AlreadyResponded:
|
||||
self.log("defer failed")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if platform.system() == "Windows":
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
@ -67,15 +142,9 @@ if __name__ == "__main__":
|
||||
|
||||
# Creates the Bot
|
||||
bot = Gwendolyn()
|
||||
bot.slash = SlashCommand(bot, sync_commands=True, sync_on_cog_reload=True, override_type=True)
|
||||
|
||||
#Loads cogs
|
||||
for filename in os.listdir("./cogs"):
|
||||
if filename.endswith(".py"):
|
||||
bot.load_extension(f"cogs.{filename[:-3]}")
|
||||
|
||||
try:
|
||||
# Runs the whole shabang
|
||||
bot.run(bot.credentials.token)
|
||||
except:
|
||||
bot.log("Could not log in. Remember to write your bot token in the credentials.txt file")
|
||||
except Exception:
|
||||
bot.log(bot.longStrings["Can't log in"])
|
||||
|
@ -1,34 +1,40 @@
|
||||
from discord.ext import commands
|
||||
"""Contains the EventCog, which runs code for specific bot events."""
|
||||
from discord.ext import commands # Has the cog class
|
||||
|
||||
|
||||
class EventCog(commands.Cog):
|
||||
"""Handles bot events."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the bot."""
|
||||
self.bot = bot
|
||||
self.bot.on_error = self.on_error
|
||||
|
||||
# Syncs commands, sets the game, and logs when the bot logs in
|
||||
@commands.Cog.listener()
|
||||
async def on_ready(self):
|
||||
"""Log and set bot status when bot logs in."""
|
||||
await self.bot.eventHandler.on_ready()
|
||||
|
||||
# Logs when user sends a command
|
||||
@commands.Cog.listener()
|
||||
async def on_slash_command(self, ctx):
|
||||
"""Log when a slash command is run."""
|
||||
await self.bot.eventHandler.on_slash_command(ctx)
|
||||
|
||||
# Logs if a command experiences an error
|
||||
@commands.Cog.listener()
|
||||
async def on_slash_command_error(self, ctx, error):
|
||||
"""Log when a slash error occurs."""
|
||||
await self.bot.errorHandler.on_slash_command_error(ctx, error)
|
||||
|
||||
# Logs if on error occurs
|
||||
async def on_error(self, method, *args, **kwargs):
|
||||
"""Log when an error occurs."""
|
||||
await self.bot.errorHandler.on_error(method)
|
||||
|
||||
# If someone reacted to a message, checks if it's a reaction it's
|
||||
# Gwendolyn has been waiting for, and then does something
|
||||
@commands.Cog.listener()
|
||||
async def on_reaction_add(self, reaction, user):
|
||||
"""Handle when someone reacts to a message."""
|
||||
await self.bot.eventHandler.on_reaction_add(reaction, user)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
"""Add the eventcog to the bot."""
|
||||
bot.add_cog(EventCog(bot))
|
||||
|
112
cogs/GameCogs.py
112
cogs/GameCogs.py
@ -1,155 +1,177 @@
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
"""Contains all the cogs that deal with game commands."""
|
||||
from discord.ext import commands # Has the cog class
|
||||
from discord_slash import cog_ext # Used for slash commands
|
||||
|
||||
from utils import getParams
|
||||
from utils import getParams # pylint: disable=import-error
|
||||
|
||||
params = getParams()
|
||||
|
||||
|
||||
class GamesCog(commands.Cog):
|
||||
def __init__(self,bot):
|
||||
"""Runs game stuff."""
|
||||
"""Contains miscellaneous game commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Checks user balance
|
||||
@cog_ext.cog_slash(**params["balance"])
|
||||
async def balance(self, ctx):
|
||||
"""Check user balance."""
|
||||
await self.bot.money.sendBalance(ctx)
|
||||
|
||||
# Gives another user an amount of GwendoBucks
|
||||
@cog_ext.cog_slash(**params["give"])
|
||||
async def give(self, ctx, user, amount):
|
||||
"""Give another user an amount of GwendoBucks."""
|
||||
await self.bot.money.giveMoney(ctx, user, amount)
|
||||
|
||||
# Invest GwendoBucks in the stock market
|
||||
@cog_ext.cog_slash(**params["invest"])
|
||||
async def invest(self, ctx, parameters = "check"):
|
||||
async def invest(self, ctx, parameters="check"):
|
||||
"""Invest GwendoBucks in the stock market."""
|
||||
await self.bot.games.invest.parseInvest(ctx, parameters)
|
||||
|
||||
# Runs a game of trivia
|
||||
@cog_ext.cog_slash(**params["trivia"])
|
||||
async def trivia(self, ctx, answer = ""):
|
||||
async def trivia(self, ctx, answer=""):
|
||||
"""Run a game of trivia."""
|
||||
await self.bot.games.trivia.triviaParse(ctx, answer)
|
||||
|
||||
|
||||
class BlackjackCog(commands.Cog):
|
||||
def __init__(self,bot):
|
||||
"""Runs game stuff."""
|
||||
"""Contains the blackjack commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Starts a game of blackjack
|
||||
@cog_ext.cog_subcommand(**params["blackjackStart"])
|
||||
async def blackjackStart(self, ctx):
|
||||
"""Start a game of blackjack."""
|
||||
await self.bot.games.blackjack.start(ctx)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackBet"])
|
||||
async def blackjackBet(self, ctx, bet):
|
||||
"""Enter the game of blackjack with a bet."""
|
||||
await self.bot.games.blackjack.playerDrawHand(ctx, bet)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackStand"])
|
||||
async def blackjackStand(self, ctx, hand = ""):
|
||||
async def blackjackStand(self, ctx, hand=""):
|
||||
"""Stand on your hand in blackjack."""
|
||||
await self.bot.games.blackjack.stand(ctx, hand)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackHit"])
|
||||
async def blackjackHit(self, ctx, hand = 0):
|
||||
async def blackjackHit(self, ctx, hand=0):
|
||||
"""Hit on your hand in blackjack."""
|
||||
await self.bot.games.blackjack.hit(ctx, hand)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackDouble"])
|
||||
async def blackjackDouble(self, ctx, hand = 0):
|
||||
async def blackjackDouble(self, ctx, hand=0):
|
||||
"""Double in blackjack."""
|
||||
await self.bot.games.blackjack.double(ctx, hand)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackSplit"])
|
||||
async def blackjackSplit(self, ctx, hand = 0):
|
||||
async def blackjackSplit(self, ctx, hand=0):
|
||||
"""Split your hand in blackjack."""
|
||||
await self.bot.games.blackjack.split(ctx, hand)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackHilo"])
|
||||
async def blackjackHilo(self, ctx):
|
||||
"""Get the hilo value for the deck in blackjack."""
|
||||
await self.bot.games.blackjack.hilo(ctx)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackShuffle"])
|
||||
async def blackjackShuffle(self, ctx):
|
||||
"""Shuffle the blackjack game."""
|
||||
await self.bot.games.blackjack.shuffle(ctx)
|
||||
|
||||
@cog_ext.cog_subcommand(**params["blackjackCards"])
|
||||
async def blackjackCards(self, ctx):
|
||||
"""Get the amount of cards left in the blackjack deck."""
|
||||
await self.bot.games.blackjack.cards(ctx)
|
||||
|
||||
|
||||
class ConnectFourCog(commands.Cog):
|
||||
def __init__(self,bot):
|
||||
"""Runs game stuff."""
|
||||
"""Contains all the connect four commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Start a game of connect four against a user
|
||||
@cog_ext.cog_subcommand(**params["connectFourStartUser"])
|
||||
async def connectFourStartUser(self, ctx, user):
|
||||
"""Start a game of connect four against another user."""
|
||||
await self.bot.games.connectFour.start(ctx, user)
|
||||
|
||||
# Start a game of connect four against gwendolyn
|
||||
@cog_ext.cog_subcommand(**params["connectFourStartGwendolyn"])
|
||||
async def connectFourStartGwendolyn(self, ctx, difficulty = 3):
|
||||
async def connectFourStartGwendolyn(self, ctx, difficulty=3):
|
||||
"""Start a game of connect four against Gwendolyn."""
|
||||
await self.bot.games.connectFour.start(ctx, difficulty)
|
||||
|
||||
# Stop the current game of connect four
|
||||
@cog_ext.cog_subcommand(**params["connectFourSurrender"])
|
||||
async def connectFourSurrender(self, ctx):
|
||||
"""Surrender the game of connect four."""
|
||||
await self.bot.games.connectFour.surrender(ctx)
|
||||
|
||||
|
||||
class HangmanCog(commands.Cog):
|
||||
def __init__(self,bot):
|
||||
"""Runs game stuff."""
|
||||
"""Contains all the hangman commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Starts a game of Hangman
|
||||
@cog_ext.cog_subcommand(**params["hangmanStart"])
|
||||
async def hangmanStart(self, ctx):
|
||||
"""Start a game of hangman."""
|
||||
await self.bot.games.hangman.start(ctx)
|
||||
|
||||
# Stops a game of Hangman
|
||||
@cog_ext.cog_subcommand(**params["hangmanStop"])
|
||||
async def hangmanStop(self, ctx):
|
||||
"""Stop the current game of hangman."""
|
||||
await self.bot.games.hangman.stop(ctx)
|
||||
|
||||
|
||||
class HexCog(commands.Cog):
|
||||
def __init__(self,bot):
|
||||
"""Runs game stuff."""
|
||||
self.bot = bot
|
||||
"""Contains all the hex commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
self.hex = self.bot.games.hex
|
||||
|
||||
# Start a game of Hex against another user
|
||||
@cog_ext.cog_subcommand(**params["hexStartUser"])
|
||||
async def hexStartUser(self, ctx, user):
|
||||
await self.bot.games.hex.start(ctx, user)
|
||||
"""Start a game of hex against another player."""
|
||||
await self.hex.start(ctx, user)
|
||||
|
||||
# Start a game of Hex against Gwendolyn
|
||||
@cog_ext.cog_subcommand(**params["hexStartGwendolyn"])
|
||||
async def hexStartGwendolyn(self, ctx, difficulty = 2):
|
||||
await self.bot.games.hex.start(ctx, difficulty)
|
||||
async def hexStartGwendolyn(self, ctx, difficulty=2):
|
||||
"""Start a game of hex against Gwendolyn."""
|
||||
await self.hex.start(ctx, difficulty)
|
||||
|
||||
# Place a piece in the hex game
|
||||
@cog_ext.cog_subcommand(**params["hexPlace"])
|
||||
async def hexPlace(self, ctx, coordinates):
|
||||
await self.bot.games.hex.placeHex(ctx, coordinates, f"#{ctx.author.id}")
|
||||
"""Place a piece in the hex game."""
|
||||
await self.hex.placeHex(ctx, coordinates, f"#{ctx.author.id}")
|
||||
|
||||
# Undo your last hex move
|
||||
@cog_ext.cog_subcommand(**params["hexUndo"])
|
||||
async def hexUndo(self, ctx):
|
||||
await self.bot.games.hex.undo(ctx)
|
||||
"""Undo your last hex move."""
|
||||
await self.hex.undo(ctx)
|
||||
|
||||
# Perform a hex swap
|
||||
@cog_ext.cog_subcommand(**params["hexSwap"])
|
||||
async def hexSwap(self, ctx):
|
||||
await self.bot.games.hex.swap(ctx)
|
||||
"""Perform a hex swap."""
|
||||
await self.hex.swap(ctx)
|
||||
|
||||
# Surrender the hex game
|
||||
@cog_ext.cog_subcommand(**params["hexSurrender"])
|
||||
async def hexSurrender(self, ctx):
|
||||
await self.bot.games.hex.surrender(ctx)
|
||||
"""Surrender the hex game."""
|
||||
await self.hex.surrender(ctx)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
"""Add all the cogs to the bot."""
|
||||
bot.add_cog(GamesCog(bot))
|
||||
bot.add_cog(BlackjackCog(bot))
|
||||
bot.add_cog(ConnectFourCog(bot))
|
||||
bot.add_cog(HangmanCog(bot))
|
||||
bot.add_cog(HexCog(bot))
|
||||
bot.add_cog(HexCog(bot))
|
||||
|
@ -1,24 +1,32 @@
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
"""Contains the LookupCog, which deals with the lookup commands."""
|
||||
from discord.ext import commands # Has the cog class
|
||||
from discord_slash import cog_ext # Used for slash commands
|
||||
|
||||
from utils import getParams
|
||||
from utils import getParams # pylint: disable=import-error
|
||||
|
||||
params = getParams()
|
||||
|
||||
|
||||
class LookupCog(commands.Cog):
|
||||
"""Contains the lookup commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Runs lookup commands."""
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Looks up a spell
|
||||
@cog_ext.cog_slash(**params["spell"])
|
||||
async def spell(self, ctx, query):
|
||||
"""Look up a spell."""
|
||||
await self.bot.lookupFuncs.spellFunc(ctx, query)
|
||||
|
||||
# Looks up a monster
|
||||
@cog_ext.cog_slash(**params["monster"])
|
||||
async def monster(self, ctx, query):
|
||||
"""Look up a monster."""
|
||||
await self.bot.lookupFuncs.monsterFunc(ctx, query)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(LookupCog(bot))
|
||||
"""Add the cog to the bot."""
|
||||
bot.add_cog(LookupCog(bot))
|
||||
|
@ -1,94 +1,99 @@
|
||||
import discord, codecs, string, json
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
"""Contains the MiscCog, which deals with miscellaneous commands."""
|
||||
from discord.ext import commands # Has the cog class
|
||||
from discord_slash import cog_ext # Used for slash commands
|
||||
|
||||
from utils import getParams # pylint: disable=import-error
|
||||
from utils import getParams # pylint: disable=import-error
|
||||
|
||||
params = getParams()
|
||||
|
||||
|
||||
class MiscCog(commands.Cog):
|
||||
"""Contains the miscellaneous commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Runs misc commands."""
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
self.bot.remove_command("help")
|
||||
self.generators = bot.other.generators
|
||||
self.bedreNetflix = bot.other.bedreNetflix
|
||||
self.nerdShit = bot.other.nerdShit
|
||||
|
||||
# Sends the bot's latency
|
||||
@cog_ext.cog_slash(**params["ping"])
|
||||
async def ping(self, ctx):
|
||||
"""Send the bot's latency."""
|
||||
await ctx.send(f"Pong!\nLatency is {round(self.bot.latency * 1000)}ms")
|
||||
|
||||
# Restarts the bot
|
||||
@cog_ext.cog_slash(**params["stop"])
|
||||
async def stop(self, ctx):
|
||||
"""Stop the bot."""
|
||||
await self.bot.stop(ctx)
|
||||
|
||||
# Gets help for specific command
|
||||
@cog_ext.cog_slash(**params["help"])
|
||||
async def helpCommand(self, ctx, command = ""):
|
||||
async def helpCommand(self, ctx, command=""):
|
||||
"""Get help for commands."""
|
||||
await self.bot.other.helpFunc(ctx, command)
|
||||
|
||||
# Lets you thank the bot
|
||||
@cog_ext.cog_slash(**params["thank"])
|
||||
async def thank(self, ctx):
|
||||
"""Thank the bot."""
|
||||
await ctx.send("You're welcome :blush:")
|
||||
|
||||
# Sends a friendly message
|
||||
@cog_ext.cog_slash(**params["hello"])
|
||||
async def hello(self, ctx):
|
||||
"""Greet the bot."""
|
||||
await self.bot.other.helloFunc(ctx)
|
||||
|
||||
# Rolls dice
|
||||
@cog_ext.cog_slash(**params["roll"])
|
||||
async def roll(self, ctx, dice = "1d20"):
|
||||
async def roll(self, ctx, dice="1d20"):
|
||||
"""Roll dice."""
|
||||
await self.bot.other.rollDice(ctx, dice)
|
||||
|
||||
# Sends a random image
|
||||
@cog_ext.cog_slash(**params["image"])
|
||||
async def image(self, ctx):
|
||||
"""Get a random image from Bing."""
|
||||
await self.bot.other.imageFunc(ctx)
|
||||
|
||||
# Finds a random movie
|
||||
@cog_ext.cog_slash(**params["movie"])
|
||||
async def movie(self, ctx):
|
||||
"""Get a random movie from the Plex server."""
|
||||
await self.bot.other.movieFunc(ctx)
|
||||
|
||||
# Generates a random name
|
||||
@cog_ext.cog_slash(**params["name"])
|
||||
async def name(self, ctx):
|
||||
"""Generate a random name."""
|
||||
await self.generators.nameGen(ctx)
|
||||
|
||||
# Generates a random tavern name
|
||||
@cog_ext.cog_slash(**params["tavern"])
|
||||
async def tavern(self, ctx):
|
||||
"""Generate a random tavern name."""
|
||||
await self.generators.tavernGen(ctx)
|
||||
|
||||
# Finds a page on the Senkulpa wiki
|
||||
@cog_ext.cog_slash(**params["wiki"])
|
||||
async def wiki(self, ctx, wikiPage = ""):
|
||||
async def wiki(self, ctx, wikiPage=""):
|
||||
"""Get a page on a fandom wiki."""
|
||||
await self.bot.other.findWikiPage(ctx, wikiPage)
|
||||
|
||||
#Searches for movie and adds it to Bedre Netflix
|
||||
@cog_ext.cog_slash(**params["addMovie"])
|
||||
async def addMovie(self, ctx, movie):
|
||||
"""Search for a movie and add it to the Plex server."""
|
||||
await self.bedreNetflix.requestMovie(ctx, movie)
|
||||
|
||||
#Searches for show and adds it to Bedre Netflix
|
||||
@cog_ext.cog_slash(**params["addShow"])
|
||||
async def addShow(self, ctx, show):
|
||||
"""Search for a show and add it to the Plex server."""
|
||||
await self.bedreNetflix.requestShow(ctx, show)
|
||||
|
||||
#Returns currently downloading torrents
|
||||
@cog_ext.cog_slash(**params["downloading"])
|
||||
async def downloading(self, ctx, parameters = "-d"):
|
||||
async def downloading(self, ctx, parameters="-d"):
|
||||
"""Get the current downloading torrents."""
|
||||
await self.bedreNetflix.downloading(ctx, parameters)
|
||||
|
||||
#Looks up on Wolfram Alpha
|
||||
@cog_ext.cog_slash(**params["wolf"])
|
||||
async def wolf(self, ctx, query):
|
||||
"""Perform a search on Wolfram Alpha."""
|
||||
await self.nerdShit.wolfSearch(ctx, query)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
"""Add the cog to the bot."""
|
||||
bot.add_cog(MiscCog(bot))
|
||||
|
@ -1,37 +1,40 @@
|
||||
import discord, string, json
|
||||
"""Contains the StarWarsCog, which deals with Star Wars commands."""
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
|
||||
from utils import getParams
|
||||
from utils import getParams # pylint: disable=import-error
|
||||
|
||||
params = getParams()
|
||||
|
||||
class starWarsCog(commands.Cog):
|
||||
|
||||
class StarWarsCog(commands.Cog):
|
||||
"""Contains the Star Wars commands."""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Runs star wars commands."""
|
||||
"""Initialize the cog."""
|
||||
self.bot = bot
|
||||
|
||||
# Rolls star wars dice
|
||||
@cog_ext.cog_slash(**params["starWarsRoll"])
|
||||
async def starWarsRoll(self, ctx, dice = ""):
|
||||
async def starWarsRoll(self, ctx, dice=""):
|
||||
"""Roll Star Wars dice."""
|
||||
await self.bot.starWars.roll.parseRoll(ctx, dice)
|
||||
|
||||
# Controls destiny points
|
||||
@cog_ext.cog_slash(**params["starWarsDestiny"])
|
||||
async def starWarsDestiny(self, ctx, parameters = ""):
|
||||
async def starWarsDestiny(self, ctx, parameters=""):
|
||||
"""Control Star Wars destiny points."""
|
||||
await self.bot.starWars.destiny.parseDestiny(ctx, parameters)
|
||||
|
||||
# Rolls for critical injuries
|
||||
@cog_ext.cog_slash(**params["starWarsCrit"])
|
||||
async def starWarsCrit(self, ctx, severity : int = 0):
|
||||
async def starWarsCrit(self, ctx, severity: int = 0):
|
||||
"""Roll for critical injuries."""
|
||||
await self.bot.starWars.roll.critRoll(ctx, severity)
|
||||
|
||||
# Accesses and changes character sheet data with the parseChar function
|
||||
# from funcs/starWarsFuncs/starWarsCharacter.py
|
||||
@cog_ext.cog_slash(**params["starWarsCharacter"])
|
||||
async def starWarsCharacter(self, ctx, parameters = ""):
|
||||
async def starWarsCharacter(self, ctx, parameters=""):
|
||||
"""Access and change Star Wars character sheet data."""
|
||||
await self.bot.starWars.character.parseChar(ctx, parameters)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(starWarsCog(bot))
|
||||
"""Add the cog to the bot."""
|
||||
bot.add_cog(StarWarsCog(bot))
|
||||
|
4
resources/longStrings.json
Normal file
4
resources/longStrings.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"missing parameters" : "Missing command parameters. Try using `!help [command]` to find out how to use the command.",
|
||||
"Can't log in": "Could not log in. Remember to write your bot token in the credentials.txt file"
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
"""A collections of utilities used by Gwendolyn and her functions"""
|
||||
"""A collections of utilities used by Gwendolyn and her functions."""
|
||||
|
||||
__all__ = ["Options", "Credentials", "databaseFuncs", "EventHandler", "ErrorHandler", "getParams", "logThis", "cap", "makeFiles", "replaceMultiple", "emojiToCommand"]
|
||||
__all__ = ["Options", "Credentials", "databaseFuncs", "EventHandler",
|
||||
"ErrorHandler", "getParams", "logThis", "cap", "makeFiles",
|
||||
"replaceMultiple", "emojiToCommand"]
|
||||
|
||||
from .helperClasses import Options, Credentials, databaseFuncs
|
||||
from .eventHandlers import EventHandler, ErrorHandler
|
||||
from .utilFunctions import getParams, logThis, cap, makeFiles, replaceMultiple, emojiToCommand
|
||||
from .utilFunctions import (getParams, logThis, cap, makeFiles,
|
||||
replaceMultiple, emojiToCommand, longStrings)
|
||||
|
@ -1,13 +1,52 @@
|
||||
import discord, traceback, discord_slash, sys
|
||||
from discord.ext import commands
|
||||
"""
|
||||
Classes used to handle bot events and errors.
|
||||
|
||||
*Classes*
|
||||
---------
|
||||
EventHandler
|
||||
ErrorHandler
|
||||
"""
|
||||
import discord # Used to init discord.Game and discord.Status, as well
|
||||
# as compare errors to discord errors and as typehints
|
||||
import traceback # Used to get the traceback of errors
|
||||
import sys # Used to get traceback when the specific error is not
|
||||
# available
|
||||
from discord.ext import commands # Used to compare errors with command
|
||||
# errors
|
||||
|
||||
from discord_slash.context import SlashContext
|
||||
from utils.utilFunctions import emojiToCommand
|
||||
|
||||
from .utilFunctions import emojiToCommand
|
||||
|
||||
class EventHandler():
|
||||
"""
|
||||
Handles bot events.
|
||||
|
||||
*Methods*
|
||||
---------
|
||||
on_ready()
|
||||
on_slash_command(ctx: discord_slash.context.SlashContext)
|
||||
on_reaction_add(ctx: discord_slash.context.SlashContext)
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the handler."""
|
||||
self.bot = bot
|
||||
|
||||
async def on_slash_command(self, ctx):
|
||||
async def on_ready(self):
|
||||
"""Log and sets status when it logs in."""
|
||||
await self.bot.databaseFuncs.syncCommands()
|
||||
name = self.bot.user.name
|
||||
userid = str(self.bot.user.id)
|
||||
loggedInMessage = f"Logged in as {name}, {userid}"
|
||||
self.bot.log(loggedInMessage, level=25)
|
||||
game = discord.Game("Use /help for commands")
|
||||
|
||||
onlineStatus = discord.Status.online
|
||||
await self.bot.change_presence(activity=game, status=onlineStatus)
|
||||
|
||||
async def on_slash_command(self, ctx: SlashContext):
|
||||
"""Log when a slash command is given."""
|
||||
if ctx.subcommand_name is not None:
|
||||
subcommand = f" {ctx.subcommand_name} "
|
||||
else:
|
||||
@ -21,100 +60,117 @@ class EventHandler():
|
||||
args = " ".join([str(i) for i in ctx.args])
|
||||
fullCommand = f"/{ctx.command}{subcommand}{subcommandGroup}{args}"
|
||||
logMessage = f"{ctx.author.display_name} ran {fullCommand}"
|
||||
self.bot.log(logMessage, str(ctx.channel_id), level = 25)
|
||||
self.bot.log(logMessage, str(ctx.channel_id), level=25)
|
||||
|
||||
async def on_ready(self):
|
||||
await self.bot.databaseFuncs.syncCommands()
|
||||
self.bot.log("Logged in as "+self.bot.user.name+", "+str(self.bot.user.id), level = 25)
|
||||
game = discord.Game("Use /help for commands")
|
||||
await self.bot.change_presence(activity=game, status = discord.Status.online)
|
||||
|
||||
async def on_reaction_add(self, reaction : discord.Reaction, user):
|
||||
if user.bot == False:
|
||||
async def on_reaction_add(self, reaction: discord.Reaction,
|
||||
user: discord.User):
|
||||
"""Take action if the reaction is on a command message."""
|
||||
if not user.bot:
|
||||
tests = self.bot.databaseFuncs
|
||||
message = reaction.message
|
||||
channel = message.channel
|
||||
self.bot.log(f"{user.display_name} reacted to a message",str(channel.id))
|
||||
try:
|
||||
connectFourTheirTurn, piece = self.bot.databaseFuncs.connectFourReactionTest(channel,message,"#"+str(user.id))
|
||||
except:
|
||||
connectFourTheirTurn = False
|
||||
reactedMessage = f"{user.display_name} reacted to a message"
|
||||
self.bot.log(reactedMessage, str(channel.id))
|
||||
plexData = tests.bedreNetflixReactionTest(message)
|
||||
# plexData is a list containing 3 elements: whether it was
|
||||
# the addshow/addmovie 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).
|
||||
|
||||
bedreNetflixMessage, addMovie, imdbIds = self.bot.databaseFuncs.bedreNetflixReactionTest(channel, message)
|
||||
reactionTestParams = [message, f"#{str(user.id)}"]
|
||||
|
||||
if connectFourTheirTurn:
|
||||
if tests.connectFourReactionTest(*reactionTestParams):
|
||||
column = emojiToCommand(reaction.emoji)
|
||||
await self.bot.games.connectFour.placePiece(message, f"#{user.id}", column-1)
|
||||
elif bedreNetflixMessage and addMovie:
|
||||
moviePick = emojiToCommand(reaction.emoji)
|
||||
if moviePick == "none":
|
||||
imdbID = None
|
||||
else:
|
||||
imdbID = imdbIds[moviePick-1]
|
||||
params = [message, f"#{user.id}", column-1]
|
||||
await self.bot.games.connectFour.placePiece(*params)
|
||||
|
||||
if isinstance(channel, discord.DMChannel):
|
||||
await message.delete()
|
||||
await self.bot.other.bedreNetflix.addMovie(message, imdbID, False)
|
||||
else:
|
||||
await message.clear_reactions()
|
||||
await self.bot.other.bedreNetflix.addMovie(message, imdbID)
|
||||
elif bedreNetflixMessage and not addMovie:
|
||||
showPick = emojiToCommand(reaction.emoji)
|
||||
if showPick == "none":
|
||||
imdbName = None
|
||||
else:
|
||||
imdbName = imdbIds[showPick-1]
|
||||
if plexData[0]:
|
||||
plexFuncs = self.bot.other.bedreNetflix
|
||||
if plexData[1]:
|
||||
moviePick = emojiToCommand(reaction.emoji)
|
||||
if moviePick == "none":
|
||||
imdbID = None
|
||||
else:
|
||||
imdbID = plexData[2][moviePick-1]
|
||||
|
||||
if isinstance(channel, discord.DMChannel):
|
||||
await message.delete()
|
||||
await self.bot.other.bedreNetflix.addShow(message, imdbName, False)
|
||||
if isinstance(channel, discord.DMChannel):
|
||||
await message.delete()
|
||||
await plexFuncs.addMovie(message, imdbID, False)
|
||||
else:
|
||||
await message.clear_reactions()
|
||||
await plexFuncs.addMovie(message, imdbID)
|
||||
else:
|
||||
await message.clear_reactions()
|
||||
await self.bot.other.bedreNetflix.addShow(message, imdbName)
|
||||
showPick = emojiToCommand(reaction.emoji)
|
||||
if showPick == "none":
|
||||
imdbName = None
|
||||
else:
|
||||
imdbName = plexData[2][showPick-1]
|
||||
|
||||
elif self.bot.databaseFuncs.hangmanReactionTest(channel, message, f"#{user.id}"):
|
||||
if isinstance(channel, discord.DMChannel):
|
||||
await message.delete()
|
||||
await plexFuncs.addShow(message, imdbName, False)
|
||||
else:
|
||||
await message.clear_reactions()
|
||||
await plexFuncs.addShow(message, imdbName)
|
||||
|
||||
elif tests.hangmanReactionTest(*reactionTestParams):
|
||||
self.bot.log("They reacted to the hangman message")
|
||||
if ord(reaction.emoji) in range(127462,127488):
|
||||
if ord(reaction.emoji) in range(127462, 127488):
|
||||
# The range is letter-emojis
|
||||
guess = chr(ord(reaction.emoji)-127397)
|
||||
await self.bot.games.hangman.guess(message, f"#{user.id}", guess)
|
||||
# Converts emoji to letter
|
||||
params = [message, f"#{user.id}", guess]
|
||||
await self.bot.games.hangman.guess(*params)
|
||||
else:
|
||||
self.bot.log("Bot they didn't react with a valid guess")
|
||||
|
||||
|
||||
class ErrorHandler():
|
||||
"""
|
||||
Handles errors.
|
||||
|
||||
*Methods*
|
||||
---------
|
||||
on_slash_command_error(ctx: discord_slash.context.SlashContext,
|
||||
error: Exception)
|
||||
on_error(method: str)
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the handler."""
|
||||
self.bot = bot
|
||||
|
||||
async def on_slash_command_error(self, ctx, error):
|
||||
async def on_slash_command_error(self, ctx: SlashContext,
|
||||
error: Exception):
|
||||
"""Log when there's a slash command."""
|
||||
if isinstance(error, commands.CommandNotFound):
|
||||
await ctx.send("That's not a command (error code 001)")
|
||||
await ctx.send("That's not a command")
|
||||
elif isinstance(error, discord.errors.NotFound):
|
||||
self.bot.log("Deleted message before I could add all reactions")
|
||||
elif isinstance(error, commands.errors.MissingRequiredArgument):
|
||||
self.bot.log(f"{error}",str(ctx.channel_id))
|
||||
await ctx.send("Missing command parameters (error code 002). Try using `!help [command]` to find out how to use the command.")
|
||||
self.bot.log(f"{error}", str(ctx.channel_id))
|
||||
await ctx.send(self.bot.longStrings["missing parameters"])
|
||||
else:
|
||||
exception = traceback.format_exception(type(error), error, error.__traceback__)
|
||||
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
|
||||
if stopAt in exception:
|
||||
index = exception.index(stopAt)
|
||||
exception = exception[:index]
|
||||
params = [type(error), error, error.__traceback__]
|
||||
exception = traceback.format_exception(*params)
|
||||
|
||||
exceptionString = "".join(exception)
|
||||
self.bot.log([f"exception in /{ctx.name}", f"{exceptionString}"],str(ctx.channel_id), 40)
|
||||
logMessages = [f"exception in /{ctx.name}", f"{exceptionString}"]
|
||||
self.bot.log(logMessages, str(ctx.channel_id), 40)
|
||||
if isinstance(error, discord.errors.NotFound):
|
||||
self.bot.log("Context is non-existant", level = 40)
|
||||
self.bot.log("Context is non-existant", level=40)
|
||||
else:
|
||||
await ctx.send("Something went wrong (error code 000)")
|
||||
|
||||
async def on_error(self, method):
|
||||
async def on_error(self, method: str):
|
||||
"""Log when there's an error."""
|
||||
errorType = sys.exc_info()[0]
|
||||
if errorType == discord.errors.NotFound:
|
||||
self.bot.log("Deleted message before I could add all reactions")
|
||||
else:
|
||||
exception = traceback.format_exc()
|
||||
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
|
||||
if stopAt in exception:
|
||||
index = exception.index(stopAt)
|
||||
exception = exception[:index]
|
||||
|
||||
exceptionString = "".join(exception)
|
||||
self.bot.log([f"exception in {method}", f"{exceptionString}"], level = 40)
|
||||
logMessages = [f"exception in {method}", f"{exceptionString}"]
|
||||
self.bot.log(logMessages, level=40)
|
||||
|
@ -1,6 +1,44 @@
|
||||
import re, git, os, json, time
|
||||
"""
|
||||
Contains classes used for utilities.
|
||||
|
||||
def sanitize(data : str, options : bool = False):
|
||||
*Functions*
|
||||
-----------
|
||||
Sanitize(data: str, lowerCaseValue: bool = false) -> dict
|
||||
|
||||
*Classes*
|
||||
---------
|
||||
Options()
|
||||
Credentials()
|
||||
DatabaseFuncs()
|
||||
"""
|
||||
import re # Used in getID
|
||||
import git # Used to pull when stopping
|
||||
import os # Used to test if files exist
|
||||
import json # Used to read the data about addmovie/addshow
|
||||
import time # Used to test how long it's been since commands were synced
|
||||
import discord # Used for type hints
|
||||
|
||||
|
||||
def sanitize(data: str, lowerCaseValue: bool = False):
|
||||
"""
|
||||
Sanitize and create a dictionary from a string.
|
||||
|
||||
Each element is created from a line with a : in it. The key is left
|
||||
of the :, the value is right of it.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
data: str
|
||||
The string to create a dict from.
|
||||
lowerCaseValue: bool = False
|
||||
Whether the value of each element should be lowercase.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
dct: dict
|
||||
The sanitized dictionary of elements.
|
||||
|
||||
"""
|
||||
data = data.splitlines()
|
||||
dct = {}
|
||||
for line in data:
|
||||
@ -8,7 +46,7 @@ def sanitize(data : str, options : bool = False):
|
||||
lineValues = line.split(":")
|
||||
lineValues[0] = lineValues[0].lower()
|
||||
lineValues[1] = lineValues[1].replace(" ", "")
|
||||
if options:
|
||||
if lowerCaseValue:
|
||||
lineValues[1] = lineValues[1].lower()
|
||||
|
||||
if lineValues[0] in ["testing guild ids", "admins"]:
|
||||
@ -23,18 +61,26 @@ def sanitize(data : str, options : bool = False):
|
||||
|
||||
return dct
|
||||
|
||||
|
||||
class Options():
|
||||
"""Contains the options for the bot."""
|
||||
|
||||
def __init__(self):
|
||||
with open("options.txt","r") as f:
|
||||
"""Initialize the options."""
|
||||
with open("options.txt", "r") as f:
|
||||
data = sanitize(f.read(), True)
|
||||
|
||||
self.testing = data["testing"]
|
||||
self.guildIds = data["testing guild ids"]
|
||||
self.admins = data["admins"]
|
||||
|
||||
|
||||
class Credentials():
|
||||
"""Contains the credentials for the bot and apis."""
|
||||
|
||||
def __init__(self):
|
||||
with open("credentials.txt","r") as f:
|
||||
"""Initialize the credentials."""
|
||||
with open("credentials.txt", "r") as f:
|
||||
data = sanitize(f.read())
|
||||
|
||||
self.token = data["bot token"]
|
||||
@ -46,34 +92,99 @@ class Credentials():
|
||||
self.radarrKey = data["radarr api key"]
|
||||
self.sonarrKey = data["sonarr api key"]
|
||||
|
||||
|
||||
class databaseFuncs():
|
||||
"""
|
||||
Manages database functions.
|
||||
|
||||
*Methods*
|
||||
---------
|
||||
getName(userID: str) -> str
|
||||
getID(userName: str) -> str
|
||||
deleteGame(gameType: str, channel: str)
|
||||
wipeGames()
|
||||
connectFourReactionTest(message: discord.Message,
|
||||
user: discord.User) -> bool
|
||||
hangmanReactionTest(message: discord.Message,
|
||||
user: discord.User) -> bool
|
||||
BedreNetflixReactionTest(message: discord.Message,
|
||||
user: discord.User) -> bool, bool,
|
||||
list
|
||||
syncCommands()
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
"""Initialize the class."""
|
||||
self.bot = bot
|
||||
|
||||
def getName(self, userID):
|
||||
user = self.bot.database["users"].find_one({"_id":userID})
|
||||
def getName(self, userID: str):
|
||||
"""
|
||||
Get the name of a user you have the # id of.
|
||||
|
||||
*Parameters:
|
||||
------------
|
||||
userID: str
|
||||
The id of the user you want the name of. The format is
|
||||
"#" + str(discord.User.id)
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
userName: str
|
||||
The name of the user. If the user couldn't be found,
|
||||
returns the userID.
|
||||
"""
|
||||
user = self.bot.database["users"].find_one({"_id": userID})
|
||||
|
||||
if userID == f"#{self.bot.user.id}":
|
||||
return "Gwendolyn"
|
||||
elif user != None:
|
||||
elif user is not None:
|
||||
return user["user name"]
|
||||
else:
|
||||
self.bot.log(f"Couldn't find user {userID}")
|
||||
return userID
|
||||
|
||||
def getID(self,userName):
|
||||
user = self.bot.database["users"].find_one({"user name":re.compile(userName, re.IGNORECASE)})
|
||||
def getID(self, userName: str):
|
||||
"""
|
||||
Get the id of a user you have the username of.
|
||||
|
||||
if user != None:
|
||||
*Parameters:
|
||||
------------
|
||||
userName: str
|
||||
The name of the user you want the id of.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
userID: str
|
||||
The id of the user in the format "#" +
|
||||
str(discord.User.id). If the user couldn't be found,
|
||||
returns the userName.
|
||||
"""
|
||||
userSearch = {"user name": re.compile(userName, re.IGNORECASE)}
|
||||
user = self.bot.database["users"].find_one(userSearch)
|
||||
|
||||
if user is not None:
|
||||
return user["_id"]
|
||||
else:
|
||||
self.bot.log("Couldn't find user "+userName)
|
||||
return None
|
||||
|
||||
def deleteGame(self, gameType, channel):
|
||||
self.bot.database[gameType].delete_one({"_id":channel})
|
||||
def deleteGame(self, gameType: str, channel: str):
|
||||
"""
|
||||
Remove a game from the database.
|
||||
|
||||
def stopServer(self):
|
||||
*Parameters*
|
||||
------------
|
||||
gameType: str
|
||||
The name of the collection the game is in, like
|
||||
"hangman games", "blackjack games" etc.
|
||||
channel: str
|
||||
The channel id of the channel the game is on as a
|
||||
string.
|
||||
"""
|
||||
self.bot.database[gameType].delete_one({"_id": channel})
|
||||
|
||||
def wipeGames(self):
|
||||
"""Delete all running games and pull from git."""
|
||||
self.bot.database["trivia questions"].delete_many({})
|
||||
self.bot.database["blackjack games"].delete_many({})
|
||||
self.bot.database["connect 4 games"].delete_many({})
|
||||
@ -84,35 +195,80 @@ class databaseFuncs():
|
||||
g = git.cmd.Git("")
|
||||
g.pull()
|
||||
|
||||
def connectFourReactionTest(self,channel,message,user):
|
||||
game = self.bot.database["connect 4 games"].find_one({"_id":str(channel.id)})
|
||||
def connectFourReactionTest(self, message: discord.Message,
|
||||
user: discord.User):
|
||||
"""
|
||||
Test if the given message is the current connect four game.
|
||||
|
||||
with open("resources/games/oldImages/connectFour"+str(channel.id), "r") as f:
|
||||
Also tests if the given user is the one who's turn it is.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
message: discord.Message
|
||||
The message to test.
|
||||
user: discord.User
|
||||
The user to test.
|
||||
*Returns*
|
||||
---------
|
||||
: bool
|
||||
Whether the given message is the current connect four
|
||||
game and if the user who reacted is the user who's turn
|
||||
it is.
|
||||
"""
|
||||
channel = message.channel
|
||||
channelSearch = {"_id": str(channel.id)}
|
||||
game = self.bot.database["connect 4 games"].find_one(channelSearch)
|
||||
|
||||
filePath = f"resources/games/oldImages/connectFour{channel.id}"
|
||||
with open(filePath, "r") as f:
|
||||
oldImage = int(f.read())
|
||||
|
||||
if message.id == oldImage:
|
||||
self.bot.log("They reacted to the connectFour game")
|
||||
turn = game["turn"]
|
||||
if user == game["players"][turn]:
|
||||
return True, turn+1
|
||||
return True
|
||||
else:
|
||||
self.bot.log("It wasn't their turn")
|
||||
return False, 0
|
||||
return False
|
||||
else:
|
||||
return False, 0
|
||||
return False
|
||||
|
||||
def hangmanReactionTest(self, channel, message, user):
|
||||
try:
|
||||
with open("resources/games/oldImages/hangman"+str(channel.id), "r") as f:
|
||||
def hangmanReactionTest(self, message: discord.Message,
|
||||
user: discord.User):
|
||||
"""
|
||||
Test if the given message is the current hangman game.
|
||||
|
||||
Also tests if the given user is the one who's playing hangman.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
message: discord.Message
|
||||
The message to test.
|
||||
user: discord.User
|
||||
The user to test.
|
||||
*Returns*
|
||||
---------
|
||||
: bool
|
||||
Whether the given message is the current hangman game
|
||||
and if the user who reacted is the user who's playing
|
||||
hangman.
|
||||
"""
|
||||
channel = message.channel
|
||||
filePath = f"resources/games/oldImages/hangman{channel.id}"
|
||||
if os.path.isfile(filePath):
|
||||
with open(filePath, "r") as f:
|
||||
oldMessages = f.read().splitlines()
|
||||
except:
|
||||
else:
|
||||
return False
|
||||
gameMessage = False
|
||||
|
||||
for oldMessage in oldMessages:
|
||||
oldMessageID = int(oldMessage)
|
||||
if message.id == oldMessageID:
|
||||
game = self.bot.database["hangman games"].find_one({"_id":str(channel.id)})
|
||||
database = self.bot.database["hangman games"]
|
||||
channelSearch = {"_id": str(channel.id)}
|
||||
game = database.find_one(channelSearch)
|
||||
if user == game["player"]:
|
||||
gameMessage = True
|
||||
|
||||
@ -120,9 +276,30 @@ class databaseFuncs():
|
||||
|
||||
return gameMessage
|
||||
|
||||
def bedreNetflixReactionTest(self, channel, message):
|
||||
if os.path.isfile(f"resources/bedreNetflix/oldMessage{str(channel.id)}"):
|
||||
with open("resources/bedreNetflix/oldMessage"+str(channel.id),"r") as f:
|
||||
def bedreNetflixReactionTest(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
|
||||
filePath = f"resources/bedreNetflix/oldMessage{str(channel.id)}"
|
||||
if os.path.isfile(filePath):
|
||||
with open(filePath, "r") as f:
|
||||
data = json.load(f)
|
||||
else:
|
||||
return False, None, None
|
||||
@ -136,6 +313,7 @@ class databaseFuncs():
|
||||
return False, None, None
|
||||
|
||||
async def syncCommands(self):
|
||||
"""Sync the slash commands with the discord API."""
|
||||
collection = self.bot.database["last synced"]
|
||||
lastSynced = collection.find_one()
|
||||
now = time.time()
|
||||
@ -144,6 +322,6 @@ class databaseFuncs():
|
||||
self.bot.log(f"Updating commands: {slashCommandList}")
|
||||
await self.bot.slash.sync_all_commands()
|
||||
idNumber = lastSynced["_id"]
|
||||
queryFilter = {"_id" : idNumber}
|
||||
update = {"$set" : {"last synced" : now}}
|
||||
queryFilter = {"_id": idNumber}
|
||||
update = {"$set": {"last synced": now}}
|
||||
collection.update_one(queryFilter, update)
|
||||
|
@ -1,3 +1,18 @@
|
||||
"""
|
||||
Contains utility functions used by parts of the bot.
|
||||
|
||||
*Functions*
|
||||
-----------
|
||||
longstrings() -> dict
|
||||
getParams() -> dict
|
||||
logThis(messages: Union[str, list], channel: str = "",
|
||||
level: int = 20)
|
||||
cap(s: str) -> str
|
||||
makeFiles()
|
||||
replaceMultiple(mainString: str, toBeReplaced: list,
|
||||
newString: str) -> str
|
||||
emojiToCommand(emoji: str) -> str
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@ -5,22 +20,55 @@ import sys
|
||||
import imdb
|
||||
from .helperClasses import Options
|
||||
|
||||
|
||||
# All of this is logging configuration
|
||||
FORMAT = " %(asctime)s | %(name)-16s | %(levelname)-8s | %(message)s"
|
||||
PRINTFORMAT = "%(asctime)s - %(message)s"
|
||||
DATEFORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
logging.addLevelName(25, "PRINT")
|
||||
logging.basicConfig(format=FORMAT, datefmt=DATEFORMAT, level=logging.INFO, filename="gwendolyn.log")
|
||||
loggingConfigParams = {
|
||||
"format": FORMAT,
|
||||
"datefmt": DATEFORMAT,
|
||||
"level": logging.INFO,
|
||||
"filename": "gwendolyn.log"
|
||||
}
|
||||
logging.basicConfig(**loggingConfigParams)
|
||||
logger = logging.getLogger("Gwendolyn")
|
||||
printer = logging.getLogger("printer")
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setFormatter(logging.Formatter(fmt = PRINTFORMAT, datefmt=DATEFORMAT))
|
||||
handler.setFormatter(logging.Formatter(fmt=PRINTFORMAT, datefmt=DATEFORMAT))
|
||||
printer.addHandler(handler)
|
||||
printer.propagate = False
|
||||
|
||||
imdb._logging.setLevel("CRITICAL")
|
||||
imdb._logging.setLevel("CRITICAL") # Basically disables imdbpy
|
||||
# logging, since it's printed to the terminal.
|
||||
|
||||
|
||||
def longStrings():
|
||||
"""
|
||||
Get the data from resources/longStrings.json.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
data: dict
|
||||
The long strings and their keys.
|
||||
"""
|
||||
with open("resources/longStrings.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def getParams():
|
||||
"""
|
||||
Get the slash command parameters.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
params: dict
|
||||
The parameters for every slash command.
|
||||
"""
|
||||
with open("resources/slashParameters.json", "r") as f:
|
||||
params = json.load(f)
|
||||
|
||||
@ -32,8 +80,25 @@ def getParams():
|
||||
|
||||
return params
|
||||
|
||||
def logThis(messages, channel : str = "", level : int = 20):
|
||||
channel = channel.replace("Direct Message with ","")
|
||||
|
||||
def logThis(messages, channel: str = "", level: int = 20):
|
||||
"""
|
||||
Log something in Gwendolyn's logs.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
messages: Union[str, list]
|
||||
A string or list of strings to be logged. If there are
|
||||
multiple strings and the level is PRINT (25) or higher,
|
||||
only the first string will be printed.
|
||||
channel: str = ""
|
||||
The channel the event to be logged occurred in. Will be
|
||||
logged along with the message(s).
|
||||
level: int = 20
|
||||
The level to log the message(s) at. If PRINT (25) or
|
||||
higher, the first message will be printed to the console.
|
||||
"""
|
||||
channel = channel.replace("Direct Message with ", "")
|
||||
if type(messages) is str:
|
||||
messages = [messages]
|
||||
|
||||
@ -41,9 +106,11 @@ def logThis(messages, channel : str = "", level : int = 20):
|
||||
|
||||
for x, msg in enumerate(messages):
|
||||
if channel != "":
|
||||
messages[x] = f"{msg} - ({channel})"
|
||||
messages[x] = f"{msg} - ({channel})" # Adds channel to log
|
||||
# messages
|
||||
|
||||
if len(messages) > 1:
|
||||
if len(messages) > 1: # Tells user to check the log if there are
|
||||
# more messages there
|
||||
printMessage += " (details in log)"
|
||||
|
||||
if level >= 25:
|
||||
@ -52,10 +119,24 @@ def logThis(messages, channel : str = "", level : int = 20):
|
||||
for logMessage in messages:
|
||||
logger.log(level, logMessage)
|
||||
|
||||
# Capitalizes all words except some of them
|
||||
def cap(s):
|
||||
no_caps_list = ["of","the"]
|
||||
# Capitalizes a strink like a movie title
|
||||
|
||||
def cap(s: str):
|
||||
"""
|
||||
Capitalize a string like a movie title.
|
||||
|
||||
That means "of" and "the" are not capitalized.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
s: str
|
||||
The string to capitalized.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
res: str
|
||||
The capitalized string.
|
||||
"""
|
||||
no_caps_list = ["of", "the"]
|
||||
word_number = 0
|
||||
lst = s.split()
|
||||
res = ''
|
||||
@ -67,22 +148,25 @@ def cap(s):
|
||||
res = res[:-1]
|
||||
return res
|
||||
|
||||
def makeFiles():
|
||||
def makeJsonFile(path,content):
|
||||
# Creates json file if it doesn't exist
|
||||
if not os.path.isfile(path):
|
||||
logThis(path.split("/")[-1]+" didn't exist. Making it now.")
|
||||
with open(path,"w") as f:
|
||||
json.dump(content,f,indent = 4)
|
||||
|
||||
def makeTxtFile(path,content):
|
||||
# Creates txt file if it doesn't exist
|
||||
def makeFiles():
|
||||
"""Create all the files and directories needed by Gwendolyn."""
|
||||
def makeJsonFile(path, content):
|
||||
"""Create json file if it doesn't exist."""
|
||||
if not os.path.isfile(path):
|
||||
logThis(path.split("/")[-1]+" didn't exist. Making it now.")
|
||||
with open(path,"w") as f:
|
||||
with open(path, "w") as f:
|
||||
json.dump(content, f, indent=4)
|
||||
|
||||
def makeTxtFile(path, content):
|
||||
"""Create txt file if it doesn't exist."""
|
||||
if not os.path.isfile(path):
|
||||
logThis(path.split("/")[-1]+" didn't exist. Making it now.")
|
||||
with open(path, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
def directory(path):
|
||||
"""Create directory if it doesn't exist."""
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
logThis("The "+path.split("/")[-1]+" directory didn't exist")
|
||||
@ -90,27 +174,58 @@ def makeFiles():
|
||||
with open("resources/startingFiles.json") as f:
|
||||
data = json.load(f)
|
||||
|
||||
for path, content in data["json"].items():
|
||||
makeJsonFile(path, content)
|
||||
|
||||
for path, content in data["txt"].items():
|
||||
makeTxtFile(path, content)
|
||||
|
||||
for path in data["folder"]:
|
||||
directory(path)
|
||||
|
||||
for path, content in data["json"].items():
|
||||
makeJsonFile(path,content)
|
||||
|
||||
for path, content in data["txt"].items():
|
||||
makeTxtFile(path,content)
|
||||
def replaceMultiple(mainString: str, toBeReplaced: list, newString: str):
|
||||
"""
|
||||
Replace multiple substrings in a string with the same substring.
|
||||
|
||||
# Replaces multiple things with the same thing
|
||||
def replaceMultiple(mainString, toBeReplaces, newString):
|
||||
*Parameters*
|
||||
------------
|
||||
mainString: str
|
||||
The string to replace substrings in.
|
||||
toBeReplaced: list
|
||||
The substrings to replace.
|
||||
newString: str
|
||||
The string to replace the substrings with.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
mainString: str
|
||||
The string with the substrings replaced.
|
||||
"""
|
||||
# Iterate over the strings to be replaced
|
||||
for elem in toBeReplaces :
|
||||
for elem in toBeReplaced:
|
||||
# Check if string is in the main string
|
||||
if elem in mainString :
|
||||
if elem in mainString:
|
||||
# Replace the string
|
||||
mainString = mainString.replace(elem, newString)
|
||||
|
||||
return mainString
|
||||
|
||||
def emojiToCommand(emoji):
|
||||
|
||||
def emojiToCommand(emoji: str):
|
||||
"""
|
||||
Convert emoji to text.
|
||||
|
||||
*Parameters*
|
||||
------------
|
||||
emoji: str
|
||||
The emoji to decipher.
|
||||
|
||||
*Returns*
|
||||
---------
|
||||
: str
|
||||
The deciphered string.
|
||||
"""
|
||||
if emoji == "1️⃣":
|
||||
return 1
|
||||
elif emoji == "2️⃣":
|
||||
@ -131,4 +246,5 @@ def emojiToCommand(emoji):
|
||||
return "none"
|
||||
elif emoji == "✔️":
|
||||
return 1
|
||||
else: return ""
|
||||
else:
|
||||
return ""
|
||||
|
Reference in New Issue
Block a user