diff --git a/.env_default b/.env_default new file mode 100644 index 0000000..c3c92fb --- /dev/null +++ b/.env_default @@ -0,0 +1,15 @@ +discord_token='token' +flask_port='5000' +imgflip_username='username' +imgflip_password='password' +openai.api_key='api_key' +upload_phixxy='False' +ftp_server='www.example.com' +ftp_username='username' +ftp_password='password' +ftp_public_html='/home/debian/www.example.com/' +stable_diffusion_ip='disabled' +stable_diffusion_port='7861' +stable_diffusion_user= +stable_diffusion_password= +eleven_labs='api-key' diff --git a/.gitignore b/.gitignore index 5637a6d..b52fbef 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ extensions/ .env databases/ channels/ -.gitignore \ No newline at end of file +.gitignore +cogs/dailies.py +cogs/idlegame.py diff --git a/cogs/chatgpt.py b/cogs/chatgpt.py index 3bf0ed8..70c3768 100644 --- a/cogs/chatgpt.py +++ b/cogs/chatgpt.py @@ -23,7 +23,6 @@ class ChatGPT(commands.Cog): self.folder_setup() self.remind_me_loop.start() self.http_session = self.create_aiohttp_session() - self.dalle_budget = self.get_budget() self.logger = logging.getLogger("bot") self.headers = { 'Content-Type': 'application/json', @@ -52,7 +51,7 @@ class ChatGPT(commands.Cog): self.logger.exception(f"ChatGPT failed to make directories: {e}") def text_cost_calc(self, model, input_tokens, output_tokens): - cost_table = {"gpt-3.5-turbo":{"input_tokens":0.0000005,"output_tokens":0.0000015}, + cost_table = {"gpt-4o-mini":{"input_tokens":0.00000015,"output_tokens":0.0000006}, "gpt-4-turbo-preview":{"input_tokens":0.00001,"output_tokens":0.00003}, "gpt-4-vision-preview":{"input_tokens":0.00001,"output_tokens":0.00003}, "gpt-4o":{"input_tokens":0.000005,"output_tokens":0.000015} @@ -61,36 +60,6 @@ class ChatGPT(commands.Cog): output_cost = cost_table[model]["output_tokens"] * output_tokens cost = input_cost + output_cost return cost - - def get_budget(self): - month = time.strftime("%B") - year = time.strftime("%Y") - key = f"{month}_{year}" - budget_file = f"{self.data_dir}budget.json" - if not os.path.exists(budget_file): - with open(budget_file, "w") as f: - json.dump({key:self.default_budget},f) - with open(budget_file, "r") as f: - budget_dict = json.loads(f.readline()) - if key not in budget_dict: - budget_dict[key] = self.default_budget - with open(budget_file, "w") as f: - json.dump(budget_dict,f) - return self.default_budget - else: - return budget_dict[key] - - def budget_add(self, amount): - month = time.strftime("%B") - year = time.strftime("%Y") - key = f"{month}_{year}" - budget_file = f"{self.data_dir}budget.json" - with open(budget_file, "r") as f: - budget_dict = json.loads(f.readline()) - budget_dict[key] += amount - with open(budget_file, "w") as f: - json.dump(budget_dict,f) - self.dalle_budget += amount def add_cost(self, category: str, cost: float): day = time.strftime("%d") @@ -155,28 +124,6 @@ class ChatGPT(commands.Cog): categories = response_data['results'][0]['categories'] category_scores = response_data['results'][0]['category_scores'] return (flagged, categories, category_scores) - - @commands.command() - async def budget(self, ctx, command=None, budget=None): - try: - if ctx.author.id == self.admin_id: - if command == "add" and budget!= None: - self.budget_add(float(budget)) - await ctx.send(f"Budget increased by {budget}") - elif command == "remove" and budget!= None: - self.budget_add(-float(budget)) - await ctx.send(f"Budget decreased by {budget}") - elif command == "set" and budget!= None: - self.budget_add(float(budget) - self.dalle_budget) - await ctx.send(f"Budget set to {budget}") - else: - await ctx.send(f"The current budget is {self.dalle_budget}") - else: - await ctx.send(f"The current budget is {self.dalle_budget}") - except Exception as e: - self.logger.exception(f"Budget command failed: {e}") - await ctx.send(f"Budget command failed") - @commands.command( name="costs", @@ -287,7 +234,7 @@ class ChatGPT(commands.Cog): user = self.bot.get_user(reminder_dict["user_id"]) return await user.send(reminder_dict["response"]) - async def answer_question(self, topic, model="gpt-3.5-turbo"): + async def answer_question(self, topic, model="gpt-4o-mini"): data = { "model": model, "messages": [{"role": "user", "content": topic}] @@ -312,6 +259,25 @@ class ChatGPT(commands.Cog): self.logger.exception("Error occurred in answer_question") return "Error occurred in answer_question" + @commands.command() + async def translate(self, ctx): + if ctx.message.attachments: + attachment = ctx.message.attachments[0] # assuming only one attachment + await attachment.save(self.working_dir + '/' + attachment.filename) + + with open(self.working_dir + '/' + attachment.filename, 'r') as file: + text = file.read() + question = f"Translate the following text to english: {text}" + # Now text contains the content of the downloaded file + translated_text = await self.answer_question(question) + # Save the translated text to a new file + with open(f'{self.working_dir}/translated_text.txt', 'w') as new_file: + new_file.write(translated_text) + + # Send the text file as an attachment + file = discord.File(f'{self.working_dir}/translated_text.txt') + await ctx.send(file=file) + @commands.command( description="Personality", @@ -402,19 +368,6 @@ class ChatGPT(commands.Cog): chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)] for chunk in chunks: await ctx.send(chunk) - - @commands.command( - description="Question GPT4", - help="Ask GPT4 a question. Usage: !question_gpt4 (question)", - brief="Get an answer" - ) - async def question_gpt4(self, ctx): - await ctx.send("One moment, let me think...") - question = ctx.message.content.split(" ", maxsplit=1)[1] - answer = await self.answer_question(question, "gpt-4o") - chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)] - for chunk in chunks: - await ctx.send(chunk) async def dalle_api_call(self, prompt: str, model: str="dall-e-2", quality: str="standard", size: str="1024x1024") -> tuple: if self.dalle_budget <= await self.get_monthly_cost(): @@ -682,7 +635,7 @@ class ChatGPT(commands.Cog): message = ctx.content[0] data = { - "model": "gpt-3.5-turbo", + "model": "gpt-4o-mini", "messages": [{"role": "system", "content": system_msg}, {"role": "user", "content": message}] } diff --git a/cogs/inky_phat.py b/cogs/inky_phat.py index deed2b2..9878834 100644 --- a/cogs/inky_phat.py +++ b/cogs/inky_phat.py @@ -146,4 +146,6 @@ class InkyScreen(commands.Cog): async def setup(bot): - await bot.add_cog(InkyScreen(bot)) \ No newline at end of file + #await bot.add_cog(InkyScreen(bot)) + #Temporarily disable as this is probably unused for everyone including me + pass \ No newline at end of file diff --git a/cogs/llama.py b/cogs/llama.py index 2712181..9e67212 100644 --- a/cogs/llama.py +++ b/cogs/llama.py @@ -159,12 +159,17 @@ class Llama(commands.Cog): channel_vars = await self.get_channel_config(message.channel.id) chat_history_string = await self.log_chat_and_get_history(message, logfile, channel_vars) # Chat Response - if channel_vars["llama_enabled"] and not message.author.bot or self.bot_id in [x.id for x in message.mentions]: - if message.content and message.content[0] != "!": - await self.chat_response(message, channel_vars, chat_history_string) - elif not message.content: - await self.chat_response(message, channel_vars, chat_history_string) + try: + if channel_vars["llama_enabled"] and not message.author.bot or self.bot_id in [x.id for x in message.mentions]: + if message.content and message.content[0] != "!": + await self.chat_response(message, channel_vars, chat_history_string) + elif not message.content: + await self.chat_response(message, channel_vars, chat_history_string) + except: + self.edit_channel_config(message.channel.id, "llama_enabled", False) async def setup(bot): - await bot.add_cog(Llama(bot)) \ No newline at end of file + #await bot.add_cog(Llama(bot)) + #Temporarily disable this as it isn't really working properly + pass \ No newline at end of file diff --git a/cogs/meshtastic.py b/cogs/meshtastic.py deleted file mode 100644 index 36f08e9..0000000 --- a/cogs/meshtastic.py +++ /dev/null @@ -1,26 +0,0 @@ -import logging -import discord -from discord.ext import commands -import meshtastic -import meshtastic.serial_interface - -class Meshtastic(commands.Cog): - - def __init__(self, bot): - self.bot = bot - self.logger = logging.getLogger("bot") - self.interface = meshtastic.serial_interface.SerialInterface() - - @commands.command( - description="Meshtastic", - help="Ask the magic ball a question.", - brief="Ask the magic ball a question.", - aliases=["mesh"] - ) - async def mesh(self, ctx, *args): - message = " ".join(args) - self.interface.sendText(message) - self.logger.info(f"Meshtastic command called by {ctx.author.name}") - -async def setup(bot): - await bot.add_cog(Meshtastic(bot)) \ No newline at end of file diff --git a/cogs/message_xp.py b/cogs/message_xp.py new file mode 100644 index 0000000..a72c98b --- /dev/null +++ b/cogs/message_xp.py @@ -0,0 +1,169 @@ +from discord.ext import commands +import discord +import json +import os +from cogs.base_cog.bot_base_cog import BotBaseCog + +class MessageXP(BotBaseCog): + + def __init__(self, bot): + super().__init__(bot) + self.setup(__class__.__name__) + + @commands.command() + async def stats(self, ctx): + author_id = str(ctx.author.id) + try: + xp_data = read_xp_file(self) + if author_id in xp_data: + level = get_level_from_xp(xp_data[author_id]) + await ctx.send(f"You are level {level} with {xp_data[author_id]} XP") + else: + await ctx.send("You have 0 XP") + except: + await ctx.send("Error getting XP") + + @commands.command() + async def show_json(self, ctx): + with open(os.path.join(self.data_dir, "xp.json"), "r") as xp_file: + xp_data = json.load(xp_file) + await ctx.send(xp_data) + + + @commands.Cog.listener() + async def on_message(self, message: discord.Message): + try: + author_id = str(message.author.id) + if message.author.bot: + return + else: + xp_data = read_xp_file(self) + if author_id in xp_data: + xp_data[author_id] += 1 + else: + xp_data[author_id] = 1 + + with open(os.path.join(self.data_dir, "xp.json"), "w") as xp_file: + json.dump(xp_data, xp_file) + except Exception as e: + self.logger.error(f"Error adding XP: {e}") + +def read_xp_file(self): + try: + with open(os.path.join(self.data_dir, "xp.json"), "r") as xp_file: + xp_data = json.load(xp_file) + return xp_data + except Exception as e: + self.logger.error(f"No XP file found. Returning empty json object: {e}") + return {} + +def get_level_from_xp(xp): + xp_dict = { + 1: 0, + 2: 83, + 3: 174, + 4: 276, + 5: 388, + 6: 512, + 7: 650, + 8: 801, + 9: 801, + 10: 1_154, + 11: 1_358, + 12: 1_584, + 13: 1_833, + 14: 2_107, + 15: 2_411, + 16: 2_746, + 17: 3_115, + 18: 3_523, + 19: 3_973, + 20: 4_470, + 21: 5_018, + 22: 5_624, + 23: 6_291, + 24: 7_028, + 25: 7_842, + 26: 8_740, + 27: 9_730, + 28: 10_824, + 29: 12_031, + 30: 13_363, + 31: 14_833, + 32: 16_456, + 33: 18_247, + 34: 20_224, + 35: 22_406, + 36: 24_815, + 37: 27_473, + 38: 30_408, + 39: 33_648, + 40: 37_224, + 41: 41_171, + 42: 45_529, + 43: 50_339, + 44: 55_649, + 45: 61_512, + 46: 67_983, + 47: 75_127, + 48: 83_014, + 49: 91_721, + 50: 101_333, + 51: 111_945, + 52: 123_660, + 53: 136_594, + 54: 150_872, + 55: 166_636, + 56: 184_040, + 57: 203_254, + 58: 224_466, + 59: 247_886, + 60: 273_742, + 61: 302_288, + 62: 333_804, + 63: 368_599, + 64: 407_015, + 65: 449_428, + 66: 496_254, + 67: 547_953, + 68: 605_032, + 69: 668_051, + 70: 737_627, + 71: 814_445, + 72: 899_257, + 73: 992_895, + 74: 1_096_278, + 75: 1_210_421, + 76: 1_336_443, + 77: 1_475_581, + 78: 1_629_200, + 79: 1_798_808, + 80: 1_986_068, + 81: 2_192_818, + 82: 2_421_087, + 83: 2_673_114, + 84: 2_951_373, + 85: 3_258_594, + 86: 3_597_792, + 87: 3_972_294, + 88: 4_385_776, + 89: 4_842_295, + 90: 5_346_332, + 91: 5_902_831, + 92: 6_517_253, + 93: 7_195_629, + 94: 7_944_614, + 95: 8_771_558, + 96: 9_684_577, + 97: 10_692_629, + 98: 11_805_606, + 99: 13_034_431 + } + for level, xp_threshold in xp_dict.items(): + if xp < xp_threshold: + return level - 1 + return 99 + + +async def setup(bot): + await bot.add_cog(MessageXP(bot)) \ No newline at end of file diff --git a/cogs/phixxycom.py b/cogs/phixxycom.py index ad8788b..84c23d4 100644 --- a/cogs/phixxycom.py +++ b/cogs/phixxycom.py @@ -192,7 +192,7 @@ class PhixxyCom(commands.Cog): except: self.logger.exception("Something went wrong in upload_ftp_ai_images") - async def answer_question(self, topic, model="gpt-3.5-turbo"): + async def answer_question(self, topic, model="gpt-4o-mini"): headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {os.getenv("openai.api_key")}', @@ -265,7 +265,7 @@ class PhixxyCom(commands.Cog): topic = await self.answer_question(question) self.logger.info("Writing blogpost") title_prompt = 'generate an absurd essay title about ' + topic - title = await self.answer_question(title_prompt, model="gpt-3.5-turbo") + title = await self.answer_question(title_prompt, model="gpt-4o-mini") prompt = 'Write a satirical essay with a serious tone titled: "' + title + '". Do not label parts of the essay.' content = await self.answer_question(prompt, model="gpt-4o") if title in content[:len(title)]: diff --git a/cogs/rss_feeds.py b/cogs/rss_feeds.py new file mode 100644 index 0000000..fd5fff6 --- /dev/null +++ b/cogs/rss_feeds.py @@ -0,0 +1,35 @@ +from discord.ext import commands, tasks +from cogs.base_cog.bot_base_cog import BotBaseCog +import feedparser +import asyncio + +class RSSCog(BotBaseCog): + + def __init__(self, bot): + super().__init__(bot) + self.setup(__class__.__name__) + self.rss_base_url = 'https://secure.runescape.com/m=adventurers-log/rssfeed?searchName=' + self.usernames = ['Deadifyed', 'Frozener', 'Tsuki no ko', 'blue boomer4'] + self.last_items = {key: None for key in self.usernames} + self.check_rss.start() + + @tasks.loop(minutes=5) + async def check_rss(self): + for name in self.usernames: + rss_url = self.rss_base_url + name.replace(' ','%20') + feed = feedparser.parse(rss_url) + latest_item = feed.entries[0] if feed.entries else None + + if latest_item and latest_item.title != self.last_items[name]: + self.last_items[name] = latest_item.title + channel = self.bot.get_channel(895388842834673696) + await channel.send(f"{name}: {latest_item.description}") + + await asyncio.sleep(60) + + @check_rss.before_loop + async def before_check_rss(self): + await self.bot.wait_until_ready() + +async def setup(bot): + await bot.add_cog(RSSCog(bot)) \ No newline at end of file diff --git a/cogs/ytdl.py b/cogs/ytdl.py new file mode 100644 index 0000000..09d2b06 --- /dev/null +++ b/cogs/ytdl.py @@ -0,0 +1,93 @@ +import os +import subprocess +import asyncio + +from discord.ext import commands, tasks +from cogs.base_cog.bot_base_cog import BotBaseCog + +class YoutubeDL(BotBaseCog): + + def __init__(self, bot): + super().__init__(bot) + self.setup(__class__.__name__) + self.check_for_downloads.start() + + ''' @commands.command() + async def youtubedl(self, ctx): + try: + # Expecting the command format to be !youtubedl + parts = ctx.message.content.split(" ") + if len(parts) < 3: + await ctx.send("Usage: !youtubedl ") + return + + url = parts[1] + video_or_audio = parts[2] + + # Run the subprocess + process = subprocess.Popen( + ["python3", "youtubedl.py", url, video_or_audio], + cwd="data/ytdl", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + + # Wait for the process to complete and read the output + stdout, stderr = process.communicate() + + # Send the output back to the user + #await ctx.send(f"std out: {stdout.decode('utf-8')}") if stdout else await ctx.send("No stdout output") + #await ctx.send(f"std err: {stderr.decode('utf-8')}") if stderr else await ctx.send("No stderr output") + await ctx.send(f"Downloading {video_or_audio} from {url}...", suppress_embeds=True) + + except Exception as e: + #await ctx.send(f"Error: {e}") + await ctx.send("Usage: !youtubedl ")''' + + @commands.command() + async def youtubedl(self, ctx): + try: + # Expecting the command format to be !youtubedl + parts = ctx.message.content.split(" ") + if len(parts) < 3: + await ctx.send("Usage: !youtubedl ") + return + + url = parts[1] + video_or_audio = parts[2] + + # Create a subprocess + process = await asyncio.create_subprocess_exec( + "python3", "youtubedl.py", url, video_or_audio, + cwd="data/ytdl", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + # Write a message that the download has started + await ctx.send(f"Downloading {video_or_audio} from {url}...") + + # Read stdout and stderr (non-blocking) + stdout, stderr = await process.communicate() + + # Send the output back to the user + if stdout: + await ctx.send(f"std out: {stdout.decode('utf-8')}") + if stderr: + await ctx.send(f"std err: {stderr.decode('utf-8')}") + + except Exception as e: + await ctx.send(f"Error: {e}") + + #create a task + @tasks.loop(seconds=10) + async def check_for_downloads(self): + for file in os.listdir("data/ytdl"): + if file.endswith(".txt"): + with open(f"data/ytdl/{file}", "r") as f: + url = f.read() + await self.bot.get_channel(544408659174883328).send(f"{url}") + os.remove(f"data/ytdl/{file}") + +async def setup(bot): + await bot.add_cog(YoutubeDL(bot)) \ No newline at end of file diff --git a/data/ytdl/youtubedl.py b/data/ytdl/youtubedl.py new file mode 100644 index 0000000..1814d03 --- /dev/null +++ b/data/ytdl/youtubedl.py @@ -0,0 +1,54 @@ +from sys import argv +import os +import time +import subprocess +#usage python3 youtubedl.py + +def download(url, video_or_audio): + if video_or_audio == "video": + process = subprocess.Popen(["yt-dlp", "--yes-playlist", f"{url}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process.wait() + return True + elif video_or_audio == "audio": + process = subprocess.Popen(["yt-dlp", "-x", "--yes-playlist", url], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process.wait() + return True + else: + print("Invalid argument") + return False + +def zip_all_files(): + #zip all files + current_epoch = time.time() + output_file = f"{current_epoch}.zip" + os.system(f"zip -r {output_file} *") + return output_file + +def upload_to_litterbox(input_file): + ''' If you want to make curl requests to the API, here is an example. Allowed values for "time" are 1h, 12h, 24h, and 72h. + curl -F "reqtype=fileupload" -F "time=1h" -F "fileToUpload=@cutie.png" https://litterbox.catbox.moe/resources/internals/api.php''' + command = f"curl -F 'reqtype=fileupload' -F 'time=1h' -F 'fileToUpload=@{input_file}' https://litterbox.catbox.moe/resources/internals/api.php" + output_url = os.popen(command).read() + #delete all files in current directory except this script + file_types = ["zip", "mp4", "mp3", "webm", "wav", "m4a", "flac", "ogg", "opus", "wma", "aac", "m4p", "m4b", "m4r", "m4v", "mp2", "mp3", "mp4", "mpa", "mpeg", "mpg", "mpv", "mxf", "ogg", "oga", "ogv", "ogx", "spx", "wav", "webm", "wma", "wv", "wvx", "weba", "webm", "webp", "wmv"] + for file in os.listdir(): + if file.split(".")[-1] in file_types: + os.remove(f"{file}") + pass + return output_url + +def main(): + url, video_or_audio = argv[1], argv[2] + print(url, video_or_audio) + if download(url, video_or_audio): + zip_file = zip_all_files() + output_url = upload_to_litterbox(zip_file) + print(output_url) + with open(f"{time.time()}.txt", "w") as output_file: + output_file.write(output_url) + output_file.close() + else: + print("Invalid argument") + +if __name__ == "__main__": + main() diff --git a/flask_templates/index.html b/flask_templates/index.html new file mode 100644 index 0000000..757eda7 --- /dev/null +++ b/flask_templates/index.html @@ -0,0 +1,73 @@ + + + + + + + + Sparkytron Config + + + +
+

Warning!

+

This information is stored in PLAIN TEXT in a .env file!

+
+ {% for key, value in key_value_pairs.items() %} +
+ +
+ +
+
+ {% endfor %} + + + + {% with messages = get_flashed_messages() %} + {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} +
+
+ + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 173a812..afdebf7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,6 @@ aiofiles inky wakeonlan beautifulsoup4 -meshtastic \ No newline at end of file +Flask[async] +waitress +feedparser \ No newline at end of file diff --git a/sparkytron_webui.py b/sparkytron_webui.py new file mode 100644 index 0000000..bb75e1e --- /dev/null +++ b/sparkytron_webui.py @@ -0,0 +1,26 @@ +import asyncio +import discord +import os +import subprocess +import sys +from dotenv import load_dotenv +from src.bot import bot +from src.webui import flask_app +from waitress import serve + +def get_flask_app(process): + flask_app.bot_process = process + flask_app.secret_key = "woaoaoahaowhawoiahoahhhhhh" + return flask_app + +def main(): + load_dotenv() + flask_port = os.getenv("flask_port") + if not flask_port: + flask_port = '5000' + process = subprocess.Popen([sys.executable, "sparkytron3000.py"]) + flask_app = get_flask_app(process) + serve(flask_app, host='0.0.0.0', port=flask_port) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/bot.py b/src/bot.py index 8c00b66..52cb604 100644 --- a/src/bot.py +++ b/src/bot.py @@ -10,7 +10,6 @@ intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) logger = src.logger.logger_setup() - async def load_cogs(bot: commands.Bot, cog_path: str) -> None: for cog_file in os.listdir(cog_path): if cog_file[-3:] == '.py': @@ -27,6 +26,7 @@ async def on_ready(): await utils.delete_all_files("tmp/") await load_cogs(bot, 'cogs/') logger.info('We have logged in as {0.user}'.format(bot)) + print("If using the webui, visit http://localhost:5000 to change config!") except: logger.warning(f"Error in on_ready") @@ -43,4 +43,4 @@ async def on_message(ctx): except discord.ext.commands.errors.CommandNotFound: logger.info("Command not found.") except Exception as e: - logger.warning(f"Error processing commands: {e}") + logger.warning(f"Error processing commands: {e}") \ No newline at end of file diff --git a/src/webui.py b/src/webui.py new file mode 100644 index 0000000..5b4306c --- /dev/null +++ b/src/webui.py @@ -0,0 +1,46 @@ +import logging +import os +import subprocess +import sys + +from flask import Flask, render_template, request, flash + +logger = logging.getLogger("bot") +flask_app = Flask(__name__, template_folder='../flask_templates') + +def read_env(filename): + if os.path.exists(filename): + with open(filename, 'r') as file: + key_value_pairs = {} + for line in file: + try: + key, value = line.strip().split('=') + key = key.strip() + value = value.strip()[1:-1] + key_value_pairs[key] = value + except: + print("This line isnt a kv pair") + return key_value_pairs + else: + return None + +@flask_app.route('/', methods=['GET', 'POST']) +async def index(): + key_value_pairs = read_env('.env') + if not key_value_pairs: + logger.warn("No .env file found! Copying defaults.") + key_value_pairs = read_env('.env_default') + form_dict = {} + if request.method == 'POST': + if key_value_pairs: + for form_name in key_value_pairs.keys(): + form_dict[form_name] = request.form[form_name] + with open('.env', 'w') as file: + for key, value in form_dict.items(): + file.write(f"{key}='{value}'\n") + flask_app.bot_process.terminate() + flask_app.bot_process = subprocess.Popen([sys.executable, "sparkytron3000.py"]) + message = "Variables Updated!" + flash(message) + return render_template('index.html', key_value_pairs = key_value_pairs) +