diff --git a/assets/fonts/Impact.ttf b/assets/fonts/Impact.ttf deleted file mode 100644 index 7b7956f..0000000 Binary files a/assets/fonts/Impact.ttf and /dev/null differ diff --git a/assets/images/attention.webp b/assets/images/attention.webp deleted file mode 100644 index f680665..0000000 Binary files a/assets/images/attention.webp and /dev/null differ diff --git a/assets/images/bibinos.png b/assets/images/bibinos.png deleted file mode 100644 index 5a7b846..0000000 Binary files a/assets/images/bibinos.png and /dev/null differ diff --git a/assets/images/crash.webp b/assets/images/crash.webp deleted file mode 100644 index 60d918b..0000000 Binary files a/assets/images/crash.webp and /dev/null differ diff --git a/assets/images/crash2.png b/assets/images/crash2.png deleted file mode 100644 index 12f7616..0000000 Binary files a/assets/images/crash2.png and /dev/null differ diff --git a/assets/images/genuineidiot.png b/assets/images/genuineidiot.png deleted file mode 100644 index 226ca47..0000000 Binary files a/assets/images/genuineidiot.png and /dev/null differ diff --git a/assets/images/smashedphone.webp b/assets/images/smashedphone.webp deleted file mode 100644 index 845070f..0000000 Binary files a/assets/images/smashedphone.webp and /dev/null differ diff --git a/assets/images/thisisfine.png b/assets/images/thisisfine.png deleted file mode 100644 index 41977dc..0000000 Binary files a/assets/images/thisisfine.png and /dev/null differ diff --git a/main.py b/main.py index 7a21e6c..3048913 100644 --- a/main.py +++ b/main.py @@ -49,7 +49,6 @@ from modules.markovmemory import * from modules.version import * from modules.sentenceprocessing import * from modules.unhandledexception import handle_exception -from modules.image import gen_meme sys.excepthook = handle_exception check_for_update() T = TypeVar('T') @@ -216,59 +215,6 @@ async def ramusage(ctx): mem = process.memory_info().rss await send_message(ctx, f"{mem / 1024 / 1024:.2f} MB") -@bot.hybrid_command(description=f"{(_('command_desc_help'))}") -async def impact(ctx: commands.Context, text: Optional[str] = None) -> None: - assets_folder = "assets/images" - - def get_random_asset_image() -> Optional[str]: - images = [f for f in os.listdir(assets_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))] - if not images: - return None - return os.path.join(assets_folder, random.choice(images)) - - temp_input = None - input_path = None - - # Determine input image path - if ctx.message.attachments: - attachment = ctx.message.attachments[0] - if attachment.content_type and attachment.content_type.startswith("image/"): - ext = os.path.splitext(attachment.filename)[1] - temp_input = f"tempy{ext}" - await attachment.save(temp_input) - input_path = temp_input - else: - fallback_image = get_random_asset_image() - if fallback_image is None: - await ctx.reply(_('no_image_available')) - return - temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1]) - shutil.copy(fallback_image, temp_input) - input_path = temp_input - else: - fallback_image = get_random_asset_image() - if fallback_image is None: - await ctx.reply(_('no_image_available')) - return - temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1]) - shutil.copy(fallback_image, temp_input) - input_path = temp_input - - # Generate meme image with one-shot text generation - output_path = await gen_meme(input_path, custom_text=text) - - if output_path is None or not os.path.isfile(output_path): - if temp_input and os.path.exists(temp_input): - os.remove(temp_input) - await ctx.reply(_('failed_generate_image')) - return - - await ctx.send(file=discord.File(output_path)) - - if temp_input and os.path.exists(temp_input): - os.remove(temp_input) - - bot.remove_command('help') # Command: Show help information @bot.hybrid_command(description=f"{(_('command_desc_help'))}") @@ -370,12 +316,10 @@ async def ping(ctx: commands.Context) -> None: LOLembed.set_footer(text=f"{(_('command_ping_footer'))} {ctx.author.name}", icon_url=ctx.author.avatar.url) await ctx.send(embed=LOLembed) -# Command: Show about information + @bot.hybrid_command(description=f"{(_('command_about_desc'))}") async def about(ctx: commands.Context) -> None: - print("-----------------------------------\n\n") - latest_version: str = check_for_update() - print("-----------------------------------") + latest_version: str = check_for_update(slient=True) embed: discord.Embed = discord.Embed(title=f"{(_('command_about_embed_title'))}", description="", color=Colour(0x000000)) embed.add_field(name=f"{(_('command_about_embed_field1'))}", value=f"{NAME}", inline=False) embed.add_field(name=f"{(_('command_about_embed_field2name'))}", value=f"{(_('command_about_embed_field2value')).format(local_version=local_version, latest_version=latest_version)}", inline=False) @@ -384,14 +328,11 @@ async def about(ctx: commands.Context) -> None: await send_message(ctx, embed=embed) -# Command: Show bot statistics (admin only) @bot.hybrid_command(description="stats") async def stats(ctx: commands.Context) -> None: if ctx.author.id != ownerid: return - print("-----------------------------------\n\n") latest_version: str = check_for_update() - print("-----------------------------------") memory_file: str = 'memory.json' file_size: int = os.path.getsize(memory_file) @@ -406,20 +347,29 @@ async def stats(ctx: commands.Context) -> None: embed.add_field(name="Python Version", value=platform.python_version()) await send_message(ctx, embed=embed) -# Command: Upload memory.json to litterbox.catbox.moe and return the link @bot.hybrid_command() async def mem(ctx: commands.Context) -> None: if showmemenabled != "true": return - command: str = """curl -F "reqtype=fileupload" -F "time=1h" -F "fileToUpload=@memory.json" https://litterbox.catbox.moe/resources/internals/api.php""" - memorylitter: subprocess.CompletedProcess = subprocess.run(command, shell=True, capture_output=True, text=True) - logger.debug(memorylitter) - await send_message(ctx, memorylitter.stdout.strip()) -# Helper: Improve sentence coherence (simple capitalization fix) + with open("memory.json", "rb") as file: + files = { + "fileToUpload": file + } + data = { + "reqtype": "fileupload", + "time": "1h" + } + + try: + response = requests.post("https://litterbox.catbox.moe/resources/internals/api.php", files=files, data=data) + response.raise_for_status() + await send_message(ctx, response.text.strip()) + except requests.RequestException as e: + logger.error(f"Upload failed: {e}") + await send_message(ctx, "Upload failed.") + def improve_sentence_coherence(sentence: str) -> str: - # Capitalizes "i" to "I" in the sentence - sentence = sentence.replace(" i ", " I ") return sentence # Start the bot diff --git a/modules/globalvars.py b/modules/globalvars.py index 78b5094..e541c7e 100644 --- a/modules/globalvars.py +++ b/modules/globalvars.py @@ -1,26 +1,19 @@ import os import platform -from dotenv import load_dotenv import pathlib +import subprocess + +from dotenv import load_dotenv import discord +from discord import Colour, Embed, File, Interaction, Message from discord.ext import commands from discord import app_commands -from discord import Colour, Embed, File, Interaction, Message from discord.abc import Messageable -from discord.ext import commands -import subprocess -def get_git_branch(): - try: - branch = subprocess.check_output( - ["git", "rev-parse", "--abbrev-ref", "HEAD"], - stderr=subprocess.DEVNULL - ).decode('utf-8').strip() - return branch - except subprocess.CalledProcessError: - return None env_path = pathlib.Path(__file__).parent.parent / '.env' load_dotenv(dotenv_path=env_path) + +# ANSI colors ANSI = "\033[" RED = f"{ANSI}31m" GREEN = f"{ANSI}32m" @@ -28,10 +21,30 @@ YELLOW = f"{ANSI}33m" PURPLE = f"{ANSI}35m" DEBUG = f"{ANSI}1;30m" RESET = f"{ANSI}0m" + VERSION_URL = "https://raw.githubusercontent.com/gooberinc/version/main" -UPDATE_URL = VERSION_URL+"/latest_version.json" +UPDATE_URL = f"{VERSION_URL}/latest_version.json" print(UPDATE_URL) -LOCAL_VERSION_FILE = "current_version.txt" + +LOCAL_VERSION_FILE = "current_version.txt" +MEMORY_FILE = "memory.json" +MEMORY_LOADED_FILE = "MEMORY_LOADED" # used in markov module +local_version = "3.0.0" +latest_version = "0.0.0" +os.environ['gooberlocal_version'] = local_version + +def get_git_branch() -> str | None: + try: + return subprocess.check_output( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + stderr=subprocess.DEVNULL + ).decode().strip() + except subprocess.CalledProcessError: + return None + +branch = get_git_branch() +beta = branch != "main" if branch else True + TOKEN = os.getenv("DISCORDBOTTOKEN", "0") PREFIX = os.getenv("BOTPREFIX", "g.") PING_LINE = os.getenv("PINGLINE") @@ -45,27 +58,23 @@ showmemenabled = os.getenv("SHOWMEMENABLED") BLACKLISTED_USERS = os.getenv("BLACKLISTEDUSERS", "").split(",") USERTRAIN_ENABLED = os.getenv("USERTRAINENABLED", "true").lower() == "true" NAME = os.getenv("NAME") -MEMORY_FILE = "memory.json" -MEMORY_LOADED_FILE = "MEMORY_LOADED" # is this still even used?? okay just checked its used in the markov module ALIVEPING = os.getenv("ALIVEPING") AUTOUPDATE = os.getenv("AUTOUPDATE") song = os.getenv("SONG") -launched = False -latest_version = "0.0.0" -local_version = "3.0.0" -os.environ['gooberlocal_version'] = local_version REACT = os.getenv("REACT") -if get_git_branch() != "main": - beta = True - # this makes goober think its a beta version, so it will not update to the latest stable version or run any version checks -else: - beta = False - -# Set up Discord bot intents and create bot instance -intents: discord.Intents = discord.Intents.default() +intents = discord.Intents.default() intents.messages = True intents.presences = True intents.members = True intents.message_content = True -bot: commands.Bot = commands.Bot(command_prefix=PREFIX, intents=intents, allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False, replied_user=True)) \ No newline at end of file + +bot = commands.Bot( + command_prefix=PREFIX, + intents=intents, + allowed_mentions=discord.AllowedMentions( + everyone=False, roles=False, users=False, replied_user=True + ) +) + +launched = False diff --git a/modules/image.py b/modules/image.py deleted file mode 100644 index 7007e5b..0000000 --- a/modules/image.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import re -import random -import shutil -import tempfile -from typing import Optional, List -from PIL import Image, ImageDraw, ImageFont, ImageOps -from modules.markovmemory import load_markov_model -from modules.sentenceprocessing import improve_sentence_coherence, rephrase_for_coherence - -generated_sentences = set() - -def load_font(size): - return ImageFont.truetype("assets/fonts/Impact.ttf", size=size) -def draw_text_with_outline(draw, text, x, y, font): - outline_offsets = [(-2, -2), (-2, 2), (2, -2), (2, 2), (0, -2), (0, 2), (-2, 0), (2, 0)] - for ox, oy in outline_offsets: - draw.text((x + ox, y + oy), text, font=font, fill="black") - draw.text((x, y), text, font=font, fill="white") - -def fits_in_width(text, font, max_width, draw): - bbox = draw.textbbox((0, 0), text, font=font) - text_width = bbox[2] - bbox[0] - return text_width <= max_width - -def split_text_to_fit(text, font, max_width, draw): - words = text.split() - for i in range(len(words), 0, -1): - top_text = " ".join(words[:i]) - bottom_text = " ".join(words[i:]) - if fits_in_width(top_text, font, max_width, draw) and fits_in_width(bottom_text, font, max_width, draw): - return top_text, bottom_text - midpoint = len(words) // 2 - return " ".join(words[:midpoint]), " ".join(words[midpoint:]) - -async def gen_meme(input_image_path, sentence_size=5, max_attempts=10, custom_text=None): - markov_model = load_markov_model() - if not markov_model or not os.path.isfile(input_image_path): - return None - - def generate_text(): - if custom_text: - return custom_text - - if sentence_size == 1: - candidate = markov_model.make_short_sentence(max_chars=100, tries=100) - if candidate: - candidate = candidate.split()[0] - return candidate - else: - candidate = markov_model.make_sentence(tries=100, max_words=sentence_size) - if candidate: - return improve_sentence_coherence(candidate) - print(candidate) - return None - - - def draw_centered_text(img, text): - draw = ImageDraw.Draw(img) - width, height = img.size - font_size = int(height / 10) - font = load_font(font_size) - - cleaned = re.sub(r'[^\w\s]', '', text).lower() - coherent = rephrase_for_coherence(cleaned).upper() - - bbox = draw.textbbox((0, 0), coherent, font=font) - text_width, text_height_px = bbox[2] - bbox[0], bbox[3] - bbox[1] - max_text_height = height // 4 - - if text_width <= width and text_height_px <= max_text_height: - draw_text_with_outline(draw, coherent, (width - text_width) / 2, 0, font) - img.save(input_image_path) - return True - - top_text, bottom_text = split_text_to_fit(coherent, font, width, draw) - top_bbox = draw.textbbox((0, 0), top_text, font=font) - bottom_bbox = draw.textbbox((0, 0), bottom_text, font=font) - - top_height = top_bbox[3] - top_bbox[1] - bottom_height = bottom_bbox[3] - bottom_bbox[1] - - if top_height <= max_text_height and bottom_height <= max_text_height: - draw_text_with_outline(draw, top_text, (width - (top_bbox[2] - top_bbox[0])) / 2, 0, font) - y_bottom = height - bottom_height - int(height * 0.04) - draw_text_with_outline(draw, bottom_text, (width - (bottom_bbox[2] - bottom_bbox[0])) / 2, y_bottom, font) - img.save(input_image_path) - return True - - return False - - attempt = 0 - while attempt < max_attempts: - response = generate_text() or "NO TEXT GENERATED" - with Image.open(input_image_path).convert("RGBA") as img: - if draw_centered_text(img, response): - return input_image_path - attempt += 1 - with Image.open(input_image_path).convert("RGBA") as img: - draw = ImageDraw.Draw(img) - width, height = img.size - font_size = int(height / 10) - font = load_font(font_size) - - truncated = (rephrase_for_coherence(re.sub(r'[^\w\s]', '', "NO TEXT GENERATED").lower()).upper())[:100] - bbox = draw.textbbox((0, 0), truncated, font=font) - text_width = bbox[2] - bbox[0] - - draw_text_with_outline(draw, truncated, (width - text_width) / 2, 0, font) - img.save(input_image_path) - return input_image_path diff --git a/modules/version.py b/modules/version.py index 37e2264..8be107f 100644 --- a/modules/version.py +++ b/modules/version.py @@ -69,7 +69,7 @@ def get_latest_version_info(): return None # Check if an update is available and perform update if needed -def check_for_update(): +def check_for_update(slient=False): global latest_version, local_version, launched latest_version_info = get_latest_version_info() @@ -89,16 +89,17 @@ def check_for_update(): logger.error(f"{RED}{_('cant_find_local_version')}{RESET}") return # Compare local and latest versions - if local_version < latest_version: - logger.info(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{RESET}") - logger.info(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}") - auto_update() - elif beta == True: - logger.warning(f"You are running an \"unstable\" version of Goober, do not expect it to work properly.\nVersion {local_version}\nServer: {latest_version}{RESET}") - elif local_version > latest_version: - logger.warning(f"{_('modification_warning')}") - elif local_version == latest_version: - logger.info(f"{_('latest_version')} {local_version}") - logger.info(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n") - launched = True + if slient != True: + if local_version < latest_version: + logger.info(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{RESET}") + logger.info(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}") + auto_update() + elif beta == True: + logger.warning(f"You are running an \"unstable\" version of Goober, do not expect it to work properly.\nVersion {local_version}\nServer: {latest_version}{RESET}") + elif local_version > latest_version: + logger.warning(f"{_('modification_warning')}") + elif local_version == latest_version: + logger.info(f"{_('latest_version')} {local_version}") + logger.info(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n") + launched = True return latest_version \ No newline at end of file