Files
Gwendolyn/gwendolyn/utils/util_functions.py
2021-08-19 13:12:15 +02:00

390 lines
11 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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 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
import string
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") 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") as file_pointer:
data = sanitize(file_pointer.read())
credentials = {}
credentials["token"] = data["bot token"]
credentials["finnhub_key"] = data["finnhub api key"]
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.
"""
with open("gwendolyn/resources/long_strings.json", "r") 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.
"""
with open("gwendolyn/resources/slash_parameters.json", "r") 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") 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") 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")
with open("gwendolyn/resources/starting_files.json") 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("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(':')