Merge pull request #22 from gooberinc/dev

Dev
This commit is contained in:
WhatDidYouExpect 2025-07-16 11:08:06 +02:00 committed by GitHub
commit 754d760252
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 205 additions and 61 deletions

View file

@ -1,8 +1,9 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
import os
from modules.globalvars import ownerid from modules.globalvars import ownerid
COG_PREFIX = "assets.cogs."
class CogManager(commands.Cog): class CogManager(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -16,7 +17,7 @@ class CogManager(commands.Cog):
await ctx.send("Please provide the cog name to load.") await ctx.send("Please provide the cog name to load.")
return return
try: try:
await self.bot.load_extension(f"cogs.{cog_name}") await self.bot.load_extension(COG_PREFIX + cog_name)
await ctx.send(f"Loaded cog `{cog_name}` successfully.") await ctx.send(f"Loaded cog `{cog_name}` successfully.")
except Exception as e: except Exception as e:
await ctx.send(f"Error loading cog `{cog_name}`: {e}") await ctx.send(f"Error loading cog `{cog_name}`: {e}")
@ -30,7 +31,7 @@ class CogManager(commands.Cog):
await ctx.send("Please provide the cog name to unload.") await ctx.send("Please provide the cog name to unload.")
return return
try: try:
await self.bot.unload_extension(f"cogs.{cog_name}") await self.bot.unload_extension(COG_PREFIX + cog_name)
await ctx.send(f"Unloaded cog `{cog_name}` successfully.") await ctx.send(f"Unloaded cog `{cog_name}` successfully.")
except Exception as e: except Exception as e:
await ctx.send(f"Error unloading cog `{cog_name}`: {e}") await ctx.send(f"Error unloading cog `{cog_name}`: {e}")
@ -44,8 +45,8 @@ class CogManager(commands.Cog):
await ctx.send("Please provide the cog name to reload.") await ctx.send("Please provide the cog name to reload.")
return return
try: try:
await self.bot.unload_extension(f"cogs.{cog_name}") await self.bot.unload_extension(COG_PREFIX + cog_name)
await self.bot.load_extension(f"cogs.{cog_name}") await self.bot.load_extension(COG_PREFIX + cog_name)
await ctx.send(f"Reloaded cog `{cog_name}` successfully.") await ctx.send(f"Reloaded cog `{cog_name}` successfully.")
except Exception as e: except Exception as e:
await ctx.send(f"Error reloading cog `{cog_name}`: {e}") await ctx.send(f"Error reloading cog `{cog_name}`: {e}")

98
assets/cogs/fuckup.py Normal file
View file

@ -0,0 +1,98 @@
import discord
from discord.ext import commands
from modules.image import *
from modules.volta.main import _
from PIL import Image, ImageEnhance, ImageFilter, ImageOps, ImageChops, ImageColor
import os, random, shutil, tempfile
async def deepfryimage(path):
with Image.open(path).convert("RGB") as im:
# make it burn
for _ in range(3):
im = im.resize((int(im.width * 0.7), int(im.height * 0.7)))
im = im.resize((int(im.width * 1.5), int(im.height * 1.5)))
im = ImageEnhance.Contrast(im).enhance(random.uniform(5, 10))
im = ImageEnhance.Sharpness(im).enhance(random.uniform(10, 50))
im = ImageEnhance.Brightness(im).enhance(random.uniform(1.5, 3))
r, g, b = im.split()
r = r.point(lambda i: min(255, i * random.uniform(1.2, 2.0)))
g = g.point(lambda i: min(255, i * random.uniform(0.5, 1.5)))
b = b.point(lambda i: min(255, i * random.uniform(0.5, 2.0)))
channels = [r, g, b]
random.shuffle(channels)
im = Image.merge("RGB", tuple(channels))
overlay_color = tuple(random.randint(0, 255) for _ in range(3))
overlay = Image.new("RGB", im.size, overlay_color)
im = ImageChops.add(im, overlay, scale=2.0, offset=random.randint(-64, 64))
im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
im = im.filter(ImageFilter.GaussianBlur(radius=random.uniform(0.5, 2)))
for _ in range(3):
tmp_path = tempfile.mktemp(suffix=".jpg")
im.save(tmp_path, format="JPEG", quality=random.randint(5, 15))
im = Image.open(tmp_path)
if random.random() < 0.3:
im = ImageOps.posterize(im, bits=random.choice([2, 3, 4]))
if random.random() < 0.2:
im = ImageOps.invert(im)
out_path = tempfile.mktemp(suffix=".jpg")
im.save(out_path, format="JPEG", quality=5)
return out_path
class whami(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
async def fuckup(self, ctx):
assets_folder = "assets/images"
temp_input = None
def get_random_asset_image():
files = [f for f in os.listdir(assets_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
if not files:
return None
return os.path.join(assets_folder, random.choice(files))
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
output_path = await gen_meme(input_path)
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
deepfried_path = await deepfryimage(output_path)
await ctx.send(file=discord.File(deepfried_path))
if temp_input and os.path.exists(temp_input):
os.remove(temp_input)
async def setup(bot):
await bot.add_cog(whami(bot))

View file

@ -1,29 +0,0 @@
import discord
from discord.ext import commands
import os
import requests
import ast
from modules.globalvars import VERSION_URL
class grabTemplate(commands.Cog):
def __init__(self, bot):
self.bot = bot
def download_json():
response = requests.get(f"{VERSION_URL}/goob/template.json")
if response.status_code == 200:
if os.path.exists("memory.json"):
return
else:
userinput = input("Do you want to download the template json instead of starting from scratch?\n(Y/N)\n")
if userinput.lower() == "y":
with open("memory.json", "w", encoding="utf-8") as file:
file.write(response.text)
else:
print("Starting from scratch...")
elif response.status_code == 404:
print("File not found on goober central!!")
download_json()
async def setup(bot):
await bot.add_cog(grabTemplate(bot))

14
bot.py
View file

@ -99,17 +99,6 @@ async def load_cogs_from_folder(bot, folder_name="assets/cogs"):
logger.error(f"{(_('cog_fail'))} {cog_name} {e}") logger.error(f"{(_('cog_fail'))} {cog_name} {e}")
traceback.print_exc() traceback.print_exc()
async def fetch_active_users() -> str:
try:
response: requests.Response = requests.get(f"{VERSION_URL}/active-users")
if response.status_code == 200:
return response.text.strip()
else:
return "?"
except Exception as e:
logger.e(f"{_('error_fetching_active_users')} {RESET} {e}")
return "?"
async def send_alive_ping_periodically() -> None: async def send_alive_ping_periodically() -> None:
while True: while True:
try: try:
@ -134,9 +123,6 @@ async def on_ready() -> None:
synced: List[discord.app_commands.AppCommand] = await bot.tree.sync() synced: List[discord.app_commands.AppCommand] = await bot.tree.sync()
logger.info(f"{_('synced_commands')} {len(synced)} {(_('synced_commands2'))}") logger.info(f"{_('synced_commands')} {len(synced)} {(_('synced_commands2'))}")
slash_commands_enabled = True slash_commands_enabled = True
active_users: str = await fetch_active_users()
logger.info(f"{(_('active_users:'))} {active_users}")
logger.info(f"{(_('started')).format(name=NAME)}") logger.info(f"{(_('started')).format(name=NAME)}")
bot.loop.create_task(send_alive_ping_periodically()) bot.loop.create_task(send_alive_ping_periodically())

View file

@ -5,11 +5,8 @@ BLACKLISTEDUSERS=
OWNERID= OWNERID=
USERTRAINENABLED="true" USERTRAINENABLED="true"
SHOWMEMENABLED="true" SHOWMEMENABLED="true"
NAME="gooberino goobs"
LOCALE=fi LOCALE=fi
ALIVEPING="True"
AUTOUPDATE="True" AUTOUPDATE="True"
GOOBERTOKEN=
SONG="Basket Case - Green Day" SONG="Basket Case - Green Day"
CHECKSDISABLED="Frue" CHECKSDISABLED="Frue"
REACT="True" REACT="True"

51
modules/coghooks.py Normal file
View file

@ -0,0 +1,51 @@
import os
import importlib
import inspect
import sys
_hooks = {}
def register_hook(name, func):
if name not in _hooks:
_hooks[name] = []
_hooks[name].append(func)
async def call_hook(name, *args, **kwargs):
if name not in _hooks:
return
for func in _hooks[name]:
if callable(func):
if inspect.iscoroutinefunction(func):
await func(*args, **kwargs)
else:
func(*args, **kwargs)
def register_all_functions_as_hooks(module):
"""Register every function/coroutine function in the given module as a hook under its function name."""
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj) or inspect.iscoroutinefunction(obj):
register_hook(name, obj)
def _register_all_modules_functions():
"""Scan all python modules in this 'modules' folder (excluding this file) and register their functions."""
# Calculate the path to the modules directory relative to this file
modules_dir = os.path.dirname(os.path.abspath(__file__))
# Current file name so we skip it
current_file = os.path.basename(__file__)
# Ensure 'modules' is in sys.path for importlib to work
if modules_dir not in sys.path:
sys.path.insert(0, modules_dir)
# List all python files except dunder files and this file
for filename in os.listdir(modules_dir):
if filename.endswith(".py") and not filename.startswith("__") and filename != current_file:
module_name = filename[:-3] # strip .py extension
try:
module = importlib.import_module(module_name)
register_all_functions_as_hooks(module)
except Exception as e:
print(f"[hooks] Failed to import {module_name}: {e}")

View file

@ -49,7 +49,7 @@ arch = platform.machine()
slash_commands_enabled = True # 100% broken, its a newer enough version so its probably enabled by default.... fix this at somepoint or hard code it in goober central code slash_commands_enabled = True # 100% broken, its a newer enough version so its probably enabled by default.... fix this at somepoint or hard code it in goober central code
launched = False launched = False
latest_version = "0.0.0" latest_version = "0.0.0"
local_version = "2.3.1" local_version = "2.3.2"
os.environ['gooberlocal_version'] = local_version os.environ['gooberlocal_version'] = local_version
REACT = os.getenv("REACT") REACT = os.getenv("REACT")
if get_git_branch() == "dev": if get_git_branch() == "dev":

View file

@ -3,6 +3,7 @@
# For updates or contributions, visit: https://github.com/gooberinc/volta # For updates or contributions, visit: https://github.com/gooberinc/volta
# Also, Note to self: Add more comments it needs more love # Also, Note to self: Add more comments it needs more love
import os import os
import locale
import json import json
import pathlib import pathlib
import threading import threading
@ -16,8 +17,6 @@ YELLOW = f"{ANSI}33m"
DEBUG = f"{ANSI}1;30m" DEBUG = f"{ANSI}1;30m"
RESET = f"{ANSI}0m" RESET = f"{ANSI}0m"
load_dotenv()
LOCALE = os.getenv("LOCALE") LOCALE = os.getenv("LOCALE")
module_dir = pathlib.Path(__file__).parent.parent module_dir = pathlib.Path(__file__).parent.parent
working_dir = pathlib.Path.cwd() working_dir = pathlib.Path.cwd()
@ -62,6 +61,37 @@ if working_dir != module_dir:
translations = {} translations = {}
_file_mod_times = {} _file_mod_times = {}
import locale
import platform
import os
import sys
def get_system_locale():
system = platform.system() # fallback incase locale isnt set
if system == "Windows":
lang, _ = locale.getdefaultlocale()
return lang or os.getenv("LANG")
elif system == "Darwin":
try:
import subprocess
result = subprocess.run(
["defaults", "read", "-g", "AppleLocale"],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True
)
return result.stdout.strip() or locale.getdefaultlocale()[0]
except Exception:
return locale.getdefaultlocale()[0]
elif system == "Linux":
return (
os.getenv("LC_ALL") or
os.getenv("LANG") or
locale.getdefaultlocale()[0]
)
return locale.getdefaultlocale()[0]
def load_translations(): def load_translations():
global translations, _file_mod_times global translations, _file_mod_times
translations.clear() translations.clear()
@ -99,7 +129,9 @@ def reload_if_changed():
def set_language(lang: str): def set_language(lang: str):
global LOCALE, ENGLISH_MISSING global LOCALE, ENGLISH_MISSING
if lang in translations: if not LOCALE:
LOCALE = get_system_locale()
elif lang in translations:
LOCALE = lang LOCALE = lang
else: else:
print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}") print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}")
@ -141,19 +173,27 @@ def check_missing_translations():
else: else:
print(f"[VOLTA] All translation keys present for locale: {LOCALE}") print(f"[VOLTA] All translation keys present for locale: {LOCALE}")
printedsystemfallback = False
def get_translation(lang: str, key: str): def get_translation(lang: str, key: str):
global printedsystemfallback
if ENGLISH_MISSING: if ENGLISH_MISSING:
return f"[VOLTA] {RED}No fallback available!{RESET}" return f"[VOLTA] {RED}No fallback available!{RESET}"
fallback_translations = translations.get(FALLBACK_LOCALE, {})
sys_lang = get_system_locale().split("_")[0] if get_system_locale() else None
sys_translations = translations.get(sys_lang, {}) if sys_lang else {}
lang_translations = translations.get(lang, {}) lang_translations = translations.get(lang, {})
if key in lang_translations: if key in lang_translations:
return lang_translations[key] return lang_translations[key]
else: if sys_lang and sys_lang != lang and key in sys_translations:
if key not in translations.get(FALLBACK_LOCALE, {}): if not printedsystemfallback:
return f"[VOLTA] {YELLOW}Missing key: '{key}' in {FALLBACK_LOCALE}.json!{RESET}" print(f"[VOLTA] {YELLOW}Falling back to system language {sys_lang}!{RESET}")
fallback = translations.get(FALLBACK_LOCALE, {}).get(key, key) printedsystemfallback = True
print(f"[VOLTA] {YELLOW}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}' using {FALLBACK_LOCALE}.json{RESET}") # yeah probably print this return sys_translations[key]
return fallback if key in fallback_translations:
print(f"[VOLTA] {YELLOW}Missing key: '{key}' in '{lang}', falling back to fallback locale '{FALLBACK_LOCALE}'{RESET}")
return fallback_translations[key]
return f"[VOLTA] {YELLOW}Missing key: '{key}' in all locales!{RESET}"
def _(key: str) -> str: def _(key: str) -> str:
return get_translation(LOCALE, key) return get_translation(LOCALE, key)