reworking a bunch of stuff

This commit is contained in:
Nikolaj
2024-10-28 13:05:06 +01:00
parent f21cbba726
commit bc59bf9b05
142 changed files with 1385 additions and 845 deletions

View File

@ -0,0 +1,391 @@
"""
Contains utility functions used by parts of the bot.
*Functions*
-----------
sanitize(data: str, lower_case_value: bool = false) -> dict
get_options() -> dict
get_credentials() -> dict
long_strings() -> dict
get_params() -> dict
log_this(messages: Union[str, list], channel: str = "",
level: int = 20)
cap(s: str) -> str
make_files()
replace_multiple(main_string: str, to_be_replaced: list,
new_string: str) -> str
emoji_to_command(emoji: str) -> str
"""
import string
import json # Used by long_strings(), get_params() and make_files()
import logging # Used for logging
import os # Used by make_files() to check if files exist
import sys # Used to specify printing for logging
import imdb # Used to disable logging for the module
BASE_37 = ":" + string.digits + string.ascii_uppercase
BASE_128 = list(
string.digits +
string.ascii_letters +
"!#$€£¢¥¤&%()*+,-./;:<=>?@[]_{|}~ `¦§©®«»±µ·¿əʒ" +
"ÆØÅÐÉÈÊÇÑÖ" +
"æøåðéèêçñö"
)
# 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")
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))
printer.addHandler(handler)
printer.propagate = False
imdb._logging.setLevel("CRITICAL") # pylint: disable=protected-access
# Basically disables imdbpy logging, since it's being printed to the
# terminal.
def sanitize(data: str, lower_case_value: 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.
lower_case_value: 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:
if line[0] != "#" and ":" in line:
line_values = line.split(":")
line_values[0] = line_values[0].lower()
line_values[1] = line_values[1].replace(" ", "")
if lower_case_value:
line_values[1] = line_values[1].lower()
if line_values[0] in ["testing guild ids", "admins"]:
line_values[1] = line_values[1].split(",")
if all(i.isnumeric() for i in line_values[1]):
line_values[1] = [int(i) for i in line_values[1]]
if any(i == line_values[1] for i in ["true", "false"]):
line_values[1] = (line_values[1] == "true")
dct[line_values[0]] = line_values[1]
return dct
def get_options():
"""
Get the bot options as dict.
*Returns*
---------
options: dict
The options of the bot.
"""
with open("options.txt", "r", encoding="utf-8") as file_pointer:
data = sanitize(file_pointer.read(), True)
options = {}
options["testing"] = data["testing"]
options["guild_ids"] = data["testing guild ids"]
options["admins"] = data["admins"]
return options
def get_credentials():
"""
Returns the credentials used by the bot as a dict.
*Returns*
---------
credentials: dict
The credentials used by the bot.
"""
with open("credentials.txt", "r", encoding="utf-8") as file_pointer:
data = sanitize(file_pointer.read())
credentials = {}
credentials["token"] = data["bot token"]
credentials["wordnik_key"] = data["wordnik api key"]
credentials["mongo_db_user"] = data["mongodb user"]
credentials["mongo_db_password"] = data["mongodb password"]
credentials["wolfram_alpha_key"] = data["wolframalpha appid"]
credentials["radarr_key"] = data["radarr api key"]
credentials["sonarr_key"] = data["sonarr api key"]
credentials["qbittorrent_username"] = data["qbittorrent username"]
credentials["qbittorrent_password"] = data["qbittorrent password"]
return credentials
def long_strings():
"""
Get the data from gwendolyn/resources/long_strings.json.
*Returns*
---------
data: dict
The long strings and their keys.
"""
long_strings_path = "gwendolyn/resources/long_strings.json"
with open(long_strings_path, "r", encoding="utf-8") as file_pointer:
data = json.load(file_pointer)
return data
def get_params():
"""
Get the slash command parameters.
*Returns*
---------
params: dict
The parameters for every slash command.
"""
path = "gwendolyn/resources/slash_parameters.json"
with open(path, "r", encoding="utf-8") as file_pointer:
slash_parameters = json.load(file_pointer)
options = get_options()
if options["testing"]:
for parameter in slash_parameters:
slash_parameters[parameter]["guild_ids"] = options["guild_ids"]
return slash_parameters
def log_this(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 isinstance(messages, str):
messages = [messages]
print_message = messages[0]
for i, message in enumerate(messages):
if channel != "":
messages[i] = f"{message} - ({channel})" # Adds channel ID
# to log messages
if len(messages) > 1: # Tells user to check the log if there are
# more messages there
print_message += " (details in log)"
if level >= 25:
printer.log(level, print_message)
for log_message in messages:
logger.log(level, log_message)
def cap(input_string: str):
"""
Capitalize a string like a movie title.
That means "of" and "the" are not capitalized.
*Parameters*
------------
input_string: str
The string to capitalized.
*Returns*
---------
return_string: str
The capitalized string.
"""
no_caps_list = ["of", "the"]
word_number = 0
string_list = input_string.split()
return_string = ''
for word in string_list:
word_number += 1
if word not in no_caps_list or word_number == 1:
word = word.capitalize()
return_string += word+" "
return_string = return_string[:-1]
return return_string
def make_files():
"""Create all the files and directories needed by Gwendolyn."""
def make_json_file(path, content):
"""Create json file if it doesn't exist."""
if not os.path.isfile(path):
log_this(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path, "w", encoding="utf-8") as file_pointer:
json.dump(content, file_pointer, indent=4)
def make_txt_file(path, content):
"""Create txt file if it doesn't exist."""
if not os.path.isfile(path):
log_this(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path, "w", encoding="utf-8") as file_pointer:
file_pointer.write(content)
def directory(path):
"""Create directory if it doesn't exist."""
if not os.path.isdir(path):
os.makedirs(path)
log_this("The "+path.split("/")[-1]+" directory didn't exist")
file_path = "gwendolyn/resources/starting_files.json"
with open(file_path, "r", encoding="utf-8") as file_pointer:
data = json.load(file_pointer)
for path, content in data["json"].items():
make_json_file(path, content)
for path, content in data["txt"].items():
make_txt_file(path, content)
for path in data["folder"]:
directory(path)
def replace_multiple(main_string: str, to_be_replaced: list, new_string: str):
"""
Replace multiple substrings in a string with the same substring.
*Parameters*
------------
main_string: str
The string to replace substrings in.
to_be_replaced: list
The substrings to replace.
new_string: str
The string to replace the substrings with.
*Returns*
---------
main_string: str
The string with the substrings replaced.
"""
# Iterate over the strings to be replaced
for elem in to_be_replaced:
# Check if string is in the main string
if elem in main_string:
# Replace the string
main_string = main_string.replace(elem, new_string)
return main_string
def emoji_to_command(emoji: str):
"""
Convert emoji to text.
*Parameters*
------------
emoji: str
The emoji to decipher.
*Returns*
---------
: str
The deciphered string.
"""
if emoji == "1":
return_value = 1
elif emoji == "2":
return_value = 2
elif emoji == "3":
return_value = 3
elif emoji == "4":
return_value = 4
elif emoji == "5":
return_value = 5
elif emoji == "6":
return_value = 6
elif emoji == "7":
return_value = 7
elif emoji == "🎲":
return_value = "roll"
elif emoji == "":
return_value = "none"
elif emoji == "✔️":
return_value = 1
else:
return_value = ""
return return_value
def encode_id(info: list):
letters = list(":".join(info))
dec = 0
for i, letter in enumerate(letters):
try:
dec += (37**i) * BASE_37.index(letter.upper())
except ValueError:
log_this(f"Could not encode letter {letter}", level=30)
custom_id = []
while dec:
custom_id.append(BASE_128[dec % 128])
dec = dec // 128
custom_id = ''.join(custom_id)
log_this(f"Encoded {info} to {custom_id}")
return custom_id
def decode_id(custom_id: str):
letters = list(custom_id)
dec = 0
for i, letter in enumerate(letters):
dec += (128**i) * BASE_128.index(letter)
info_string = []
while dec:
info_string.append(BASE_37[dec % 37])
dec = dec // 37
info = ''.join(info_string).split(':')
log_this(f"Decoded {custom_id} to be {info}")
return ''.join(info_string).split(':')