forked from gooberinc/goober
commit
754d760252
8 changed files with 205 additions and 61 deletions
|
@ -1,8 +1,9 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
import os
|
||||
from modules.globalvars import ownerid
|
||||
|
||||
COG_PREFIX = "assets.cogs."
|
||||
|
||||
class CogManager(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -16,7 +17,7 @@ class CogManager(commands.Cog):
|
|||
await ctx.send("Please provide the cog name to load.")
|
||||
return
|
||||
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.")
|
||||
except Exception as 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.")
|
||||
return
|
||||
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.")
|
||||
except Exception as 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.")
|
||||
return
|
||||
try:
|
||||
await self.bot.unload_extension(f"cogs.{cog_name}")
|
||||
await self.bot.load_extension(f"cogs.{cog_name}")
|
||||
await self.bot.unload_extension(COG_PREFIX + cog_name)
|
||||
await self.bot.load_extension(COG_PREFIX + cog_name)
|
||||
await ctx.send(f"Reloaded cog `{cog_name}` successfully.")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Error reloading cog `{cog_name}`: {e}")
|
||||
|
|
98
assets/cogs/fuckup.py
Normal file
98
assets/cogs/fuckup.py
Normal 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))
|
|
@ -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
14
bot.py
|
@ -99,17 +99,6 @@ async def load_cogs_from_folder(bot, folder_name="assets/cogs"):
|
|||
logger.error(f"{(_('cog_fail'))} {cog_name} {e}")
|
||||
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:
|
||||
while True:
|
||||
try:
|
||||
|
@ -134,9 +123,6 @@ async def on_ready() -> None:
|
|||
synced: List[discord.app_commands.AppCommand] = await bot.tree.sync()
|
||||
logger.info(f"{_('synced_commands')} {len(synced)} {(_('synced_commands2'))}")
|
||||
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)}")
|
||||
|
||||
bot.loop.create_task(send_alive_ping_periodically())
|
||||
|
|
|
@ -5,11 +5,8 @@ BLACKLISTEDUSERS=
|
|||
OWNERID=
|
||||
USERTRAINENABLED="true"
|
||||
SHOWMEMENABLED="true"
|
||||
NAME="gooberino goobs"
|
||||
LOCALE=fi
|
||||
ALIVEPING="True"
|
||||
AUTOUPDATE="True"
|
||||
GOOBERTOKEN=
|
||||
SONG="Basket Case - Green Day"
|
||||
CHECKSDISABLED="Frue"
|
||||
REACT="True"
|
||||
|
|
51
modules/coghooks.py
Normal file
51
modules/coghooks.py
Normal 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}")
|
||||
|
||||
|
|
@ -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
|
||||
launched = False
|
||||
latest_version = "0.0.0"
|
||||
local_version = "2.3.1"
|
||||
local_version = "2.3.2"
|
||||
os.environ['gooberlocal_version'] = local_version
|
||||
REACT = os.getenv("REACT")
|
||||
if get_git_branch() == "dev":
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# For updates or contributions, visit: https://github.com/gooberinc/volta
|
||||
# Also, Note to self: Add more comments it needs more love
|
||||
import os
|
||||
import locale
|
||||
import json
|
||||
import pathlib
|
||||
import threading
|
||||
|
@ -16,8 +17,6 @@ YELLOW = f"{ANSI}33m"
|
|||
DEBUG = f"{ANSI}1;30m"
|
||||
RESET = f"{ANSI}0m"
|
||||
|
||||
load_dotenv()
|
||||
|
||||
LOCALE = os.getenv("LOCALE")
|
||||
module_dir = pathlib.Path(__file__).parent.parent
|
||||
working_dir = pathlib.Path.cwd()
|
||||
|
@ -62,6 +61,37 @@ if working_dir != module_dir:
|
|||
translations = {}
|
||||
_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():
|
||||
global translations, _file_mod_times
|
||||
translations.clear()
|
||||
|
@ -99,7 +129,9 @@ def reload_if_changed():
|
|||
|
||||
def set_language(lang: str):
|
||||
global LOCALE, ENGLISH_MISSING
|
||||
if lang in translations:
|
||||
if not LOCALE:
|
||||
LOCALE = get_system_locale()
|
||||
elif lang in translations:
|
||||
LOCALE = lang
|
||||
else:
|
||||
print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}")
|
||||
|
@ -141,19 +173,27 @@ def check_missing_translations():
|
|||
else:
|
||||
print(f"[VOLTA] All translation keys present for locale: {LOCALE}")
|
||||
|
||||
printedsystemfallback = False
|
||||
|
||||
def get_translation(lang: str, key: str):
|
||||
global printedsystemfallback
|
||||
if ENGLISH_MISSING:
|
||||
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, {})
|
||||
if key in lang_translations:
|
||||
return lang_translations[key]
|
||||
else:
|
||||
if key not in translations.get(FALLBACK_LOCALE, {}):
|
||||
return f"[VOLTA] {YELLOW}Missing key: '{key}' in {FALLBACK_LOCALE}.json!{RESET}"
|
||||
fallback = translations.get(FALLBACK_LOCALE, {}).get(key, key)
|
||||
print(f"[VOLTA] {YELLOW}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}' using {FALLBACK_LOCALE}.json{RESET}") # yeah probably print this
|
||||
return fallback
|
||||
if sys_lang and sys_lang != lang and key in sys_translations:
|
||||
if not printedsystemfallback:
|
||||
print(f"[VOLTA] {YELLOW}Falling back to system language {sys_lang}!{RESET}")
|
||||
printedsystemfallback = True
|
||||
return sys_translations[key]
|
||||
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:
|
||||
return get_translation(LOCALE, key)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue