forked from gooberinc/goober
added permission wrapper
This commit is contained in:
parent
f7042ed8a7
commit
f186e079da
29 changed files with 860 additions and 788 deletions
|
@ -2,23 +2,23 @@ import discord
|
|||
from discord.ext import commands
|
||||
import discord.ext
|
||||
import discord.ext.commands
|
||||
from modules.permission import requires_admin
|
||||
from modules.settings import Settings as SettingsManager
|
||||
|
||||
settings_manager = SettingsManager()
|
||||
settings = settings_manager.settings
|
||||
|
||||
|
||||
COG_PREFIX = "assets.cogs."
|
||||
|
||||
|
||||
class CogManager(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def enable(self, ctx, cog_name: str):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
|
||||
try:
|
||||
await self.bot.load_extension(COG_PREFIX + cog_name)
|
||||
await ctx.send(f"Loaded cog `{cog_name}` successfully.")
|
||||
|
@ -28,17 +28,13 @@ class CogManager(commands.Cog):
|
|||
except Exception as e:
|
||||
await ctx.send(f"Error enabling cog `{cog_name}`: {e}")
|
||||
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def load(self, ctx, cog_name: str | None = None):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
|
||||
if cog_name is None:
|
||||
await ctx.send("Give cog_name")
|
||||
return
|
||||
|
||||
|
||||
if cog_name[:-3] not in settings["bot"]["enabled_cogs"]:
|
||||
await ctx.send("Please enable the cog first!")
|
||||
return
|
||||
|
@ -51,11 +47,9 @@ class CogManager(commands.Cog):
|
|||
except Exception as e:
|
||||
await ctx.send(f"Error loading cog `{cog_name}`: {e}")
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def unload(self, ctx, cog_name: str | None = None):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
if cog_name is None:
|
||||
await ctx.send("Please provide the cog name to unload.")
|
||||
return
|
||||
|
@ -65,11 +59,9 @@ class CogManager(commands.Cog):
|
|||
except Exception as e:
|
||||
await ctx.send(f"Error unloading cog `{cog_name}`: {e}")
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def disable(self, ctx, cog_name: str | None = None):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
if cog_name is None:
|
||||
await ctx.send("Please provide the cog name to disable.")
|
||||
return
|
||||
|
@ -81,12 +73,9 @@ class CogManager(commands.Cog):
|
|||
except Exception as e:
|
||||
await ctx.send(f"Error unloading cog `{cog_name}`: {e}")
|
||||
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def reload(self, ctx, cog_name: str | None = None):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
if cog_name is None:
|
||||
await ctx.send("Please provide the cog name to reload.")
|
||||
return
|
||||
|
@ -109,9 +98,13 @@ class CogManager(commands.Cog):
|
|||
await ctx.send("No cogs are currently loaded.")
|
||||
return
|
||||
|
||||
embed = discord.Embed(title="Loaded Cogs", description="Here is a list of all currently loaded cogs:")
|
||||
embed = discord.Embed(
|
||||
title="Loaded Cogs",
|
||||
description="Here is a list of all currently loaded cogs:",
|
||||
)
|
||||
embed.add_field(name="Cogs", value="\n".join(cogs), inline=False)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(CogManager(bot))
|
||||
|
|
|
@ -2,36 +2,40 @@ import random
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class eightball(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command()
|
||||
async def eightball(self, ctx):
|
||||
answer = random.choice([
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Without a doubt.",
|
||||
"Yes definitely.",
|
||||
"You may rely on it.",
|
||||
"As I see it, yes.",
|
||||
"Most likely.",
|
||||
"Outlook good.",
|
||||
"Yes.",
|
||||
"Signs point to yes.",
|
||||
"Reply hazy, try again.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
"Don't count on it.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook not so good.",
|
||||
"Very doubtful."
|
||||
])
|
||||
answer = random.choice(
|
||||
[
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Without a doubt.",
|
||||
"Yes definitely.",
|
||||
"You may rely on it.",
|
||||
"As I see it, yes.",
|
||||
"Most likely.",
|
||||
"Outlook good.",
|
||||
"Yes.",
|
||||
"Signs point to yes.",
|
||||
"Reply hazy, try again.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
"Don't count on it.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook not so good.",
|
||||
"Very doubtful.",
|
||||
]
|
||||
)
|
||||
|
||||
await ctx.send(answer)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(eightball(bot))
|
||||
|
|
|
@ -3,7 +3,9 @@ import discord.context_managers
|
|||
from discord.ext import commands
|
||||
import logging
|
||||
from typing import Literal, get_args, cast
|
||||
from modules.permission import requires_admin
|
||||
from modules.settings import Settings as SettingsManager
|
||||
|
||||
settings_manager = SettingsManager()
|
||||
settings = settings_manager.settings
|
||||
|
||||
|
@ -12,6 +14,7 @@ logger = logging.getLogger("goober")
|
|||
|
||||
AvailableModes = Literal["r", "s"]
|
||||
|
||||
|
||||
class FileSync(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot: discord.Client = bot
|
||||
|
@ -19,24 +22,21 @@ class FileSync(commands.Cog):
|
|||
self.peer_id = None
|
||||
self.awaiting_file = False
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def syncfile(self, ctx: commands.Context, mode: str, peer: discord.User):
|
||||
if self.mode not in get_args(AvailableModes):
|
||||
await ctx.send("Invalid mode, use 's' or 'r'.")
|
||||
return
|
||||
|
||||
|
||||
self.mode = cast(AvailableModes, mode.lower())
|
||||
self.peer_id = peer.id
|
||||
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You don't have permission to execute this command.")
|
||||
return
|
||||
|
||||
if self.mode == "s":
|
||||
await ctx.send(f"<@{self.peer_id}> FILE_TRANSFER_REQUEST")
|
||||
await ctx.send(file=discord.File("memory.json"))
|
||||
await ctx.send("File sent in this channel.")
|
||||
|
||||
|
||||
elif self.mode == "r":
|
||||
await ctx.send("Waiting for incoming file...")
|
||||
self.awaiting_file = True
|
||||
|
@ -53,12 +53,11 @@ class FileSync(commands.Cog):
|
|||
logger.info("Ping received. Awaiting file...")
|
||||
if not message.attachments:
|
||||
return
|
||||
|
||||
|
||||
for attachment in message.attachments:
|
||||
if not attachment.filename.endswith(".json"):
|
||||
continue
|
||||
|
||||
|
||||
filename = "received_memory.json"
|
||||
with open(filename, "wb") as f:
|
||||
await attachment.save(f)
|
||||
|
@ -67,5 +66,6 @@ class FileSync(commands.Cog):
|
|||
await message.channel.send("File received and saved.")
|
||||
self.awaiting_file = False
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(FileSync(bot))
|
||||
|
|
|
@ -5,6 +5,7 @@ from PIL import Image, ImageEnhance, ImageFilter, ImageOps, ImageChops, ImageCol
|
|||
import os, random, shutil, tempfile
|
||||
import modules.keys as k
|
||||
|
||||
|
||||
async def deepfryimage(path):
|
||||
with Image.open(path).convert("RGB") as im:
|
||||
# make it burn
|
||||
|
@ -44,14 +45,17 @@ 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'))]
|
||||
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))
|
||||
|
@ -94,5 +98,6 @@ class whami(commands.Cog):
|
|||
if temp_input and os.path.exists(temp_input):
|
||||
os.remove(temp_input)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(whami(bot))
|
||||
|
|
|
@ -6,11 +6,12 @@ from dotenv import load_dotenv
|
|||
|
||||
load_dotenv()
|
||||
|
||||
#stole most of this code from my old expect bot so dont be suprised if its poorly made
|
||||
# stole most of this code from my old expect bot so dont be suprised if its poorly made
|
||||
|
||||
LASTFM_API_KEY = os.getenv("LASTFM_API_KEY")
|
||||
LASTFM_USERNAME = os.getenv("LASTFM_USERNAME")
|
||||
|
||||
|
||||
class LastFmCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -34,7 +35,11 @@ class LastFmCog(commands.Cog):
|
|||
self.current_track = track
|
||||
artist, song = track
|
||||
activity_name = f"{artist} - {song}"
|
||||
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=activity_name))
|
||||
await self.bot.change_presence(
|
||||
activity=discord.Activity(
|
||||
type=discord.ActivityType.listening, name=activity_name
|
||||
)
|
||||
)
|
||||
print(f"Updated song to {artist} - {song}")
|
||||
else:
|
||||
print("LastFM gave me the same track! not updating...")
|
||||
|
@ -52,7 +57,11 @@ class LastFmCog(commands.Cog):
|
|||
self.current_track = track
|
||||
artist, song = track
|
||||
activity_name = f"{artist} - {song}"
|
||||
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=activity_name))
|
||||
await self.bot.change_presence(
|
||||
activity=discord.Activity(
|
||||
type=discord.ActivityType.listening, name=activity_name
|
||||
)
|
||||
)
|
||||
await ctx.send(f"Updated presence to: Listening to {activity_name}")
|
||||
|
||||
async def fetch_current_track(self):
|
||||
|
@ -71,12 +80,13 @@ class LastFmCog(commands.Cog):
|
|||
return None
|
||||
|
||||
track = recenttracks[0]
|
||||
if '@attr' in track and track['@attr'].get('nowplaying') == 'true':
|
||||
artist = track.get('artist', {}).get('#text', 'Unknown Artist')
|
||||
song = track.get('name', 'Unknown Song')
|
||||
if "@attr" in track and track["@attr"].get("nowplaying") == "true":
|
||||
artist = track.get("artist", {}).get("#text", "Unknown Artist")
|
||||
song = track.get("name", "Unknown Song")
|
||||
return artist, song
|
||||
return None
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
if not LASTFM_API_KEY or not LASTFM_USERNAME:
|
||||
return
|
||||
|
|
|
@ -2,10 +2,13 @@ from discord.ext import commands
|
|||
import discord
|
||||
from collections import defaultdict, Counter
|
||||
import datetime
|
||||
from modules.permission import requires_admin
|
||||
from modules.settings import Settings as SettingsManager
|
||||
|
||||
settings_manager = SettingsManager()
|
||||
settings = settings_manager.settings
|
||||
|
||||
|
||||
class StatsCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -32,38 +35,54 @@ class StatsCog(commands.Cog):
|
|||
async def on_command(self, ctx):
|
||||
self.command_usage[ctx.command.qualified_name] += 1
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def spyware(self, ctx):
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
return
|
||||
uptime = datetime.datetime.utcnow() - self.start_time
|
||||
hours_elapsed = max((uptime.total_seconds() / 3600), 1)
|
||||
avg_per_hour = self.total_messages / hours_elapsed
|
||||
if self.messages_per_hour:
|
||||
peak_hour, peak_count = max(self.messages_per_hour.items(), key=lambda x: x[1])
|
||||
peak_hour, peak_count = max(
|
||||
self.messages_per_hour.items(), key=lambda x: x[1]
|
||||
)
|
||||
else:
|
||||
peak_hour, peak_count = "N/A", 0
|
||||
|
||||
top_users = self.user_message_counts.most_common(5)
|
||||
|
||||
embed = discord.Embed(title="Community Stats", color=discord.Color.blue())
|
||||
embed.add_field(name="Uptime", value=str(uptime).split('.')[0], inline=False)
|
||||
embed.add_field(name="Total Messages", value=str(self.total_messages), inline=True)
|
||||
embed.add_field(name="Active Users", value=str(len(self.active_users)), inline=True)
|
||||
embed.add_field(name="Avg Messages/Hour", value=f"{avg_per_hour:.2f}", inline=True)
|
||||
embed.add_field(name="Peak Hour (UTC)", value=f"{peak_hour}: {peak_count} messages", inline=True)
|
||||
embed.add_field(name="Uptime", value=str(uptime).split(".")[0], inline=False)
|
||||
embed.add_field(
|
||||
name="Total Messages", value=str(self.total_messages), inline=True
|
||||
)
|
||||
embed.add_field(
|
||||
name="Active Users", value=str(len(self.active_users)), inline=True
|
||||
)
|
||||
embed.add_field(
|
||||
name="Avg Messages/Hour", value=f"{avg_per_hour:.2f}", inline=True
|
||||
)
|
||||
embed.add_field(
|
||||
name="Peak Hour (UTC)",
|
||||
value=f"{peak_hour}: {peak_count} messages",
|
||||
inline=True,
|
||||
)
|
||||
|
||||
top_str = "\n".join(
|
||||
f"<@{user_id}>: {count} messages" for user_id, count in top_users
|
||||
) or "No data"
|
||||
top_str = (
|
||||
"\n".join(f"<@{user_id}>: {count} messages" for user_id, count in top_users)
|
||||
or "No data"
|
||||
)
|
||||
embed.add_field(name="Top Chatters", value=top_str, inline=False)
|
||||
|
||||
cmd_str = "\n".join(
|
||||
f"{cmd}: {count}" for cmd, count in self.command_usage.most_common(5)
|
||||
) or "No commands used yet"
|
||||
cmd_str = (
|
||||
"\n".join(
|
||||
f"{cmd}: {count}" for cmd, count in self.command_usage.most_common(5)
|
||||
)
|
||||
or "No commands used yet"
|
||||
)
|
||||
embed.add_field(name="Top Commands", value=cmd_str, inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(StatsCog(bot))
|
||||
|
|
|
@ -2,6 +2,7 @@ import discord
|
|||
from discord.ext import commands
|
||||
from discord import app_commands
|
||||
|
||||
|
||||
class Ping(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -12,11 +13,15 @@ class Ping(commands.Cog):
|
|||
exampleembed = discord.Embed(
|
||||
title="Pong!!",
|
||||
description="The Beretta fires fast and won't make you feel any better!",
|
||||
color=discord.Color.blue()
|
||||
color=discord.Color.blue(),
|
||||
)
|
||||
exampleembed.set_footer(
|
||||
text=f"Requested by {interaction.user.name}",
|
||||
icon_url=interaction.user.avatar.url,
|
||||
)
|
||||
exampleembed.set_footer(text=f"Requested by {interaction.user.name}", icon_url=interaction.user.avatar.url)
|
||||
|
||||
await interaction.followup.send(embed=exampleembed)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Ping(bot))
|
||||
|
|
|
@ -3,6 +3,7 @@ from discord.ext import commands
|
|||
from modules.globalvars import RED, GREEN, RESET, LOCAL_VERSION_FILE
|
||||
import os
|
||||
|
||||
|
||||
class songchange(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -19,15 +20,22 @@ class songchange(commands.Cog):
|
|||
@commands.command()
|
||||
async def changesong(self, ctx):
|
||||
if LOCAL_VERSION_FILE > "0.11.8":
|
||||
await ctx.send(f"Goober is too old! you must have version 0.11.8 you have {local_version}")
|
||||
await ctx.send(
|
||||
f"Goober is too old! you must have version 0.11.8 you have {local_version}"
|
||||
)
|
||||
return
|
||||
await ctx.send("Check the terminal! (this does not persist across restarts)")
|
||||
song = input("\nEnter a song:\n")
|
||||
try:
|
||||
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"{song}"))
|
||||
await self.bot.change_presence(
|
||||
activity=discord.Activity(
|
||||
type=discord.ActivityType.listening, name=f"{song}"
|
||||
)
|
||||
)
|
||||
print(f"{GREEN}Changed song to {song}{RESET}")
|
||||
except Exception as e:
|
||||
print(f"{RED}An error occurred while changing songs..: {str(e)}{RESET}")
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(songchange(bot))
|
||||
|
|
|
@ -13,20 +13,22 @@ ready = True
|
|||
MODEL_MATCH_STRING = r"[0-9]{2}_[0-9]{2}_[0-9]{4}-[0-9]{2}_[0-9]{2}"
|
||||
|
||||
try:
|
||||
import tensorflow as tf
|
||||
import tensorflow as tf
|
||||
import keras
|
||||
from keras.preprocessing.text import Tokenizer
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
from keras.models import Sequential, load_model
|
||||
from keras.layers import Embedding, LSTM, Dense
|
||||
from keras.backend import clear_session
|
||||
|
||||
if tf.config.list_physical_devices('GPU'):
|
||||
|
||||
if tf.config.list_physical_devices("GPU"):
|
||||
print("Using GPU acceleration")
|
||||
elif tf.config.list_physical_devices('Metal'):
|
||||
elif tf.config.list_physical_devices("Metal"):
|
||||
print("Using Metal for macOS acceleration")
|
||||
except ImportError:
|
||||
print("ERROR: Failed to import TensorFlow. Ensure you have the correct dependencies:")
|
||||
print(
|
||||
"ERROR: Failed to import TensorFlow. Ensure you have the correct dependencies:"
|
||||
)
|
||||
print("tensorflow>=2.15.0")
|
||||
print("For macOS (Apple Silicon): tensorflow-metal")
|
||||
ready = False
|
||||
|
@ -38,24 +40,39 @@ class TFCallback(keras.callbacks.Callback):
|
|||
self.bot = bot
|
||||
self.message = message
|
||||
self.times = [time.time()]
|
||||
|
||||
|
||||
async def send_message(self, message: str, description: str, **kwargs):
|
||||
if "epoch" in kwargs:
|
||||
self.times.append(time.time())
|
||||
avg_epoch_time = np.mean(np.diff(self.times))
|
||||
description = f"ETA: {round(avg_epoch_time)}s"
|
||||
self.embed.add_field(name=f"<t:{round(time.time())}:t> - {message}", value=description, inline=False)
|
||||
self.embed.add_field(
|
||||
name=f"<t:{round(time.time())}:t> - {message}",
|
||||
value=description,
|
||||
inline=False,
|
||||
)
|
||||
await self.message.edit(embed=self.embed)
|
||||
|
||||
|
||||
def on_train_end(self, logs=None):
|
||||
self.bot.loop.create_task(self.send_message("Training stopped", "Training has been stopped."))
|
||||
|
||||
self.bot.loop.create_task(
|
||||
self.send_message("Training stopped", "Training has been stopped.")
|
||||
)
|
||||
|
||||
def on_epoch_begin(self, epoch, logs=None):
|
||||
self.bot.loop.create_task(self.send_message(f"Starting epoch {epoch}", "This might take a while", epoch=True))
|
||||
|
||||
self.bot.loop.create_task(
|
||||
self.send_message(
|
||||
f"Starting epoch {epoch}", "This might take a while", epoch=True
|
||||
)
|
||||
)
|
||||
|
||||
def on_epoch_end(self, epoch, logs=None):
|
||||
self.bot.loop.create_task(self.send_message(f"Epoch {epoch} ended", f"Accuracy: {round(logs.get('accuracy', 0.0), 4)}"))
|
||||
|
||||
self.bot.loop.create_task(
|
||||
self.send_message(
|
||||
f"Epoch {epoch} ended",
|
||||
f"Accuracy: {round(logs.get('accuracy', 0.0), 4)}",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Ai:
|
||||
def __init__(self):
|
||||
|
@ -63,11 +80,11 @@ class Ai:
|
|||
if model_path:
|
||||
self.__load_model(model_path)
|
||||
self.is_loaded = model_path is not None
|
||||
self.batch_size = 64
|
||||
|
||||
self.batch_size = 64
|
||||
|
||||
def generate_model_name(self):
|
||||
return time.strftime('%d_%m_%Y-%H_%M', time.localtime())
|
||||
|
||||
return time.strftime("%d_%m_%Y-%H_%M", time.localtime())
|
||||
|
||||
def __load_model(self, model_path):
|
||||
clear_session()
|
||||
self.model = load_model(os.path.join(model_path, "model.h5"))
|
||||
|
@ -81,7 +98,7 @@ class Ai:
|
|||
with open("memory.json", "r") as f:
|
||||
self.tokenizer.fit_on_texts(json.load(f))
|
||||
self.is_loaded = True
|
||||
|
||||
|
||||
def reload_model(self):
|
||||
clear_session()
|
||||
model_path = settings.get("model_path")
|
||||
|
@ -90,9 +107,11 @@ class Ai:
|
|||
self.is_loaded = True
|
||||
|
||||
async def run_async(self, func, bot, *args, **kwargs):
|
||||
return await bot.loop.run_in_executor(None, functools.partial(func, *args, **kwargs))
|
||||
return await bot.loop.run_in_executor(
|
||||
None, functools.partial(func, *args, **kwargs)
|
||||
)
|
||||
|
||||
|
||||
|
||||
class Learning(Ai):
|
||||
def create_model(self, memory, epochs=2):
|
||||
memory = memory[:2000]
|
||||
|
@ -107,41 +126,58 @@ class Learning(Ai):
|
|||
maxlen = max(map(len, X))
|
||||
X = pad_sequences(X, maxlen=maxlen, padding="pre")
|
||||
y = np.array(y)
|
||||
|
||||
model = Sequential([
|
||||
Embedding(input_dim=VOCAB_SIZE, output_dim=128, input_length=maxlen),
|
||||
LSTM(64),
|
||||
Dense(VOCAB_SIZE, activation="softmax")
|
||||
])
|
||||
|
||||
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
|
||||
|
||||
model = Sequential(
|
||||
[
|
||||
Embedding(input_dim=VOCAB_SIZE, output_dim=128, input_length=maxlen),
|
||||
LSTM(64),
|
||||
Dense(VOCAB_SIZE, activation="softmax"),
|
||||
]
|
||||
)
|
||||
|
||||
model.compile(
|
||||
optimizer="adam",
|
||||
loss="sparse_categorical_crossentropy",
|
||||
metrics=["accuracy"],
|
||||
)
|
||||
history = model.fit(X, y, epochs=epochs, batch_size=64, callbacks=[tf_callback])
|
||||
self.save_model(model, tokenizer, history)
|
||||
|
||||
|
||||
def save_model(self, model, tokenizer, history, name=None):
|
||||
name = name or self.generate_model_name()
|
||||
model_dir = os.path.join("models", name)
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
|
||||
|
||||
with open(os.path.join(model_dir, "info.json"), "w") as f:
|
||||
json.dump(history.history, f)
|
||||
with open(os.path.join(model_dir, "tokenizer.pkl"), "wb") as f:
|
||||
pickle.dump(tokenizer, f)
|
||||
model.save(os.path.join(model_dir, "model.h5"))
|
||||
|
||||
|
||||
|
||||
class Generation(Ai):
|
||||
def generate_sentence(self, word_amount, seed):
|
||||
if not self.is_loaded:
|
||||
return False
|
||||
for _ in range(word_amount):
|
||||
token_list = self.tokenizer.texts_to_sequences([seed])[0]
|
||||
token_list = pad_sequences([token_list], maxlen=self.model.input_shape[1], padding="pre")
|
||||
predicted_word_index = np.argmax(self.model.predict(token_list, verbose=0), axis=-1)[0]
|
||||
output_word = next((w for w, i in self.tokenizer.word_index.items() if i == predicted_word_index), "")
|
||||
token_list = pad_sequences(
|
||||
[token_list], maxlen=self.model.input_shape[1], padding="pre"
|
||||
)
|
||||
predicted_word_index = np.argmax(
|
||||
self.model.predict(token_list, verbose=0), axis=-1
|
||||
)[0]
|
||||
output_word = next(
|
||||
(
|
||||
w
|
||||
for w, i in self.tokenizer.word_index.items()
|
||||
if i == predicted_word_index
|
||||
),
|
||||
"",
|
||||
)
|
||||
seed += " " + output_word
|
||||
return seed
|
||||
|
||||
|
||||
|
||||
VOCAB_SIZE = 100_000
|
||||
settings = {}
|
||||
|
@ -152,4 +188,4 @@ tf_callback = None
|
|||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Tf(bot))
|
||||
await bot.add_cog(Tf(bot))
|
||||
|
|
|
@ -5,10 +5,13 @@ from bs4 import BeautifulSoup
|
|||
import json
|
||||
import asyncio
|
||||
from urllib.parse import urljoin
|
||||
from modules.permission import requires_admin
|
||||
from modules.settings import Settings as SettingsManager
|
||||
|
||||
settings_manager = SettingsManager()
|
||||
settings = settings_manager.settings
|
||||
|
||||
|
||||
class WebScraper(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -25,7 +28,7 @@ class WebScraper(commands.Cog):
|
|||
|
||||
def extract_sentences(self, text):
|
||||
"""Extract sentences from text."""
|
||||
sentences = text.split('.')
|
||||
sentences = text.split(".")
|
||||
return [sentence.strip() for sentence in sentences if sentence.strip()]
|
||||
|
||||
def save_to_json(self, sentences):
|
||||
|
@ -52,7 +55,6 @@ class WebScraper(commands.Cog):
|
|||
print("No data to undo.")
|
||||
return False
|
||||
|
||||
|
||||
data = data[:-1]
|
||||
|
||||
with open("memory.json", "w") as file:
|
||||
|
@ -76,18 +78,14 @@ class WebScraper(commands.Cog):
|
|||
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
|
||||
for paragraph in soup.find_all('p'):
|
||||
for paragraph in soup.find_all("p"):
|
||||
sentences = self.extract_sentences(paragraph.get_text())
|
||||
self.save_to_json(sentences)
|
||||
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def start_scrape(self, ctx, start_url: str):
|
||||
"""Command to start the scraping process."""
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
|
||||
if not start_url.startswith("http"):
|
||||
await ctx.send("Please provide a valid URL.")
|
||||
return
|
||||
|
@ -99,18 +97,16 @@ class WebScraper(commands.Cog):
|
|||
|
||||
await ctx.send("Scraping complete! Sentences saved to memory.json.")
|
||||
|
||||
@requires_admin()
|
||||
@commands.command()
|
||||
async def undo_scrape(self, ctx):
|
||||
"""Command to undo the last scrape."""
|
||||
if ctx.author.id not in settings["bot"]["owner_ids"]:
|
||||
await ctx.send("You do not have permission to use this command.")
|
||||
return
|
||||
|
||||
success = self.undo_last_scrape()
|
||||
if success:
|
||||
await ctx.send("Last scrape undone successfully.")
|
||||
else:
|
||||
await ctx.send("No data to undo or an error occurred.")
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(WebScraper(bot))
|
||||
|
|
|
@ -14,6 +14,7 @@ from modules.globalvars import VERSION_URL
|
|||
import sys
|
||||
import subprocess
|
||||
|
||||
|
||||
class GooberWeb(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -24,18 +25,20 @@ class GooberWeb(commands.Cog):
|
|||
self.last_command_time = "Never"
|
||||
self.start_time = time.time()
|
||||
self.websockets = set()
|
||||
|
||||
self.app.add_routes([
|
||||
web.get('/', self.handle_index),
|
||||
web.get('/changesong', self.handle_changesong),
|
||||
web.get('/stats', self.handle_stats),
|
||||
web.get('/data', self.handle_json_data),
|
||||
web.get('/ws', self.handle_websocket),
|
||||
web.get('/styles.css', self.handle_css),
|
||||
web.get('/settings', self.handle_settings),
|
||||
web.post('/update_settings', self.handle_update_settings),
|
||||
web.post('/restart_bot', self.handle_restart_bot),
|
||||
])
|
||||
|
||||
self.app.add_routes(
|
||||
[
|
||||
web.get("/", self.handle_index),
|
||||
web.get("/changesong", self.handle_changesong),
|
||||
web.get("/stats", self.handle_stats),
|
||||
web.get("/data", self.handle_json_data),
|
||||
web.get("/ws", self.handle_websocket),
|
||||
web.get("/styles.css", self.handle_css),
|
||||
web.get("/settings", self.handle_settings),
|
||||
web.post("/update_settings", self.handle_update_settings),
|
||||
web.post("/restart_bot", self.handle_restart_bot),
|
||||
]
|
||||
)
|
||||
|
||||
self.bot.loop.create_task(self.start_web_server())
|
||||
self.update_clients.start()
|
||||
|
@ -52,72 +55,82 @@ class GooberWeb(commands.Cog):
|
|||
async def get_blacklisted_users(self):
|
||||
blacklisted_ids = os.getenv("BLACKLISTED_USERS", "").split(",")
|
||||
blacklisted_users = []
|
||||
|
||||
|
||||
for user_id in blacklisted_ids:
|
||||
if not user_id.strip():
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
user = await self.bot.fetch_user(int(user_id))
|
||||
blacklisted_users.append({
|
||||
"name": f"{user.name}",
|
||||
"avatar_url": str(user.avatar.url) if user.avatar else str(user.default_avatar.url),
|
||||
"id": user.id
|
||||
})
|
||||
blacklisted_users.append(
|
||||
{
|
||||
"name": f"{user.name}",
|
||||
"avatar_url": (
|
||||
str(user.avatar.url)
|
||||
if user.avatar
|
||||
else str(user.default_avatar.url)
|
||||
),
|
||||
"id": user.id,
|
||||
}
|
||||
)
|
||||
except discord.NotFound:
|
||||
blacklisted_users.append({
|
||||
"name": f"Unknown User ({user_id})",
|
||||
"avatar_url": "",
|
||||
"id": user_id
|
||||
})
|
||||
blacklisted_users.append(
|
||||
{
|
||||
"name": f"Unknown User ({user_id})",
|
||||
"avatar_url": "",
|
||||
"id": user_id,
|
||||
}
|
||||
)
|
||||
except discord.HTTPException as e:
|
||||
print(f"Error fetching user {user_id}: {e}")
|
||||
continue
|
||||
|
||||
|
||||
return blacklisted_users
|
||||
|
||||
|
||||
async def get_enhanced_guild_info(self):
|
||||
guilds = sorted(self.bot.guilds, key=lambda g: g.member_count, reverse=True)
|
||||
guild_info = []
|
||||
|
||||
|
||||
for guild in guilds:
|
||||
icon_url = str(guild.icon.url) if guild.icon else ""
|
||||
guild_info.append({
|
||||
"name": guild.name,
|
||||
"member_count": guild.member_count,
|
||||
"icon_url": icon_url,
|
||||
"id": guild.id
|
||||
})
|
||||
|
||||
guild_info.append(
|
||||
{
|
||||
"name": guild.name,
|
||||
"member_count": guild.member_count,
|
||||
"icon_url": icon_url,
|
||||
"id": guild.id,
|
||||
}
|
||||
)
|
||||
|
||||
return guild_info
|
||||
|
||||
|
||||
async def start_web_server(self):
|
||||
self.runner = web.AppRunner(self.app)
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, '0.0.0.0', 8080)
|
||||
self.site = web.TCPSite(self.runner, "0.0.0.0", 8080)
|
||||
await self.site.start()
|
||||
print("Goober web server started on port 8080")
|
||||
|
||||
|
||||
async def stop_web_server(self):
|
||||
if self.site is None or self.runner is None:
|
||||
return
|
||||
|
||||
|
||||
await self.site.stop()
|
||||
await self.runner.cleanup()
|
||||
print("Web server stopped")
|
||||
|
||||
|
||||
def cog_unload(self):
|
||||
self.update_clients.cancel()
|
||||
self.bot.loop.create_task(self.stop_web_server())
|
||||
|
||||
|
||||
@tasks.loop(seconds=5)
|
||||
async def update_clients(self):
|
||||
if not self.websockets:
|
||||
return
|
||||
|
||||
|
||||
stats = await self.get_bot_stats()
|
||||
message = json.dumps(stats)
|
||||
|
||||
|
||||
for ws in set(self.websockets):
|
||||
try:
|
||||
await ws.send_str(message)
|
||||
|
@ -126,62 +139,62 @@ class GooberWeb(commands.Cog):
|
|||
except Exception as e:
|
||||
print(f"Error sending to websocket: {e}")
|
||||
self.websockets.remove(ws)
|
||||
|
||||
|
||||
async def handle_websocket(self, request):
|
||||
ws = web.WebSocketResponse()
|
||||
await ws.prepare(request)
|
||||
self.websockets.add(ws)
|
||||
|
||||
|
||||
try:
|
||||
async for msg in ws:
|
||||
if msg.type == WSMsgType.ERROR:
|
||||
print(f"WebSocket error: {ws.exception()}")
|
||||
finally:
|
||||
self.websockets.remove(ws)
|
||||
|
||||
|
||||
return ws
|
||||
|
||||
|
||||
async def handle_css(self, request):
|
||||
css_path = os.path.join(os.path.dirname(__file__), 'styles.css')
|
||||
css_path = os.path.join(os.path.dirname(__file__), "styles.css")
|
||||
if os.path.exists(css_path):
|
||||
return web.FileResponse(css_path)
|
||||
return web.Response(text="CSS file not found", status=404)
|
||||
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
|
||||
ctx = await self.bot.get_context(message)
|
||||
if ctx.valid and ctx.command:
|
||||
self._update_command_stats(ctx.command.name, ctx.author)
|
||||
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_app_command_completion(self, interaction, command):
|
||||
self._update_command_stats(command.name, interaction.user)
|
||||
|
||||
|
||||
def _update_command_stats(self, command_name, user):
|
||||
self.last_command = f"{command_name} (by {user.name})"
|
||||
self.last_command_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
if self.websockets:
|
||||
asyncio.create_task(self.update_clients())
|
||||
|
||||
|
||||
async def get_bot_stats(self):
|
||||
process = psutil.Process(os.getpid())
|
||||
mem_info = process.memory_full_info()
|
||||
cpu_percent = psutil.cpu_percent()
|
||||
process_cpu = process.cpu_percent()
|
||||
|
||||
|
||||
memory_json_size = "N/A"
|
||||
if os.path.exists("memory.json"):
|
||||
memory_json_size = f"{os.path.getsize('memory.json') / 1024:.2f} KB"
|
||||
|
||||
|
||||
guild_info = await self.get_enhanced_guild_info()
|
||||
blacklisted_users = await self.get_blacklisted_users()
|
||||
|
||||
|
||||
uptime_seconds = int(time.time() - self.start_time)
|
||||
uptime_str = f"{uptime_seconds // 86400}d {(uptime_seconds % 86400) // 3600}h {(uptime_seconds % 3600) // 60}m {uptime_seconds % 60}s"
|
||||
|
||||
|
||||
return {
|
||||
"ram_usage": f"{mem_info.rss / 1024 / 1024:.2f} MB",
|
||||
"cpu_usage": f"{process_cpu}%",
|
||||
|
@ -196,23 +209,29 @@ class GooberWeb(commands.Cog):
|
|||
"bot_uptime": uptime_str,
|
||||
"latency": f"{self.bot.latency * 1000:.2f} ms",
|
||||
"bot_name": self.bot.user.name,
|
||||
"bot_avatar_url": str(self.bot.user.avatar.url) if self.bot.user.avatar else "",
|
||||
"bot_avatar_url": (
|
||||
str(self.bot.user.avatar.url) if self.bot.user.avatar else ""
|
||||
),
|
||||
"authenticated": os.getenv("gooberauthenticated"),
|
||||
"lastmsg": os.getenv("gooberlatestgen"),
|
||||
"localversion": os.getenv("gooberlocal_version"),
|
||||
"latestversion": os.getenv("gooberlatest_version"),
|
||||
"owner": os.getenv("ownerid")
|
||||
"owner": os.getenv("ownerid"),
|
||||
}
|
||||
|
||||
|
||||
async def handle_update(self, request):
|
||||
if os.path.exists("goob/update.py"):
|
||||
return web.FileResponse("goob/update.py")
|
||||
return web.Response(text="Update file not found", status=404)
|
||||
|
||||
async def handle_changesong(self, request):
|
||||
song = request.query.get('song', '')
|
||||
song = request.query.get("song", "")
|
||||
if song:
|
||||
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=song))
|
||||
await self.bot.change_presence(
|
||||
activity=discord.Activity(
|
||||
type=discord.ActivityType.listening, name=song
|
||||
)
|
||||
)
|
||||
return web.Response(text=f"Changed song to: {song}")
|
||||
return web.Response(text="Please provide a song parameter", status=400)
|
||||
|
||||
|
@ -224,36 +243,37 @@ class GooberWeb(commands.Cog):
|
|||
async def read_env_file(self):
|
||||
env_vars = {}
|
||||
try:
|
||||
with open('.env', 'r') as f:
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#') or '=' not in line:
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
|
||||
key, value = line.split('=', 1)
|
||||
key, value = line.split("=", 1)
|
||||
key = key.strip()
|
||||
if key in ['splashtext', 'DISCORD_BOT_TOKEN']:
|
||||
if key in ["splashtext", "DISCORD_BOT_TOKEN"]:
|
||||
continue
|
||||
|
||||
env_vars[key] = value.strip('"\'')
|
||||
env_vars[key] = value.strip("\"'")
|
||||
except FileNotFoundError:
|
||||
print(".env file not found")
|
||||
return env_vars
|
||||
|
||||
|
||||
async def handle_settings(self, request):
|
||||
env_vars = await self.read_env_file()
|
||||
|
||||
|
||||
# Get config.py variables
|
||||
config_vars = {}
|
||||
try:
|
||||
with open('config.py', 'r') as f:
|
||||
with open("config.py", "r") as f:
|
||||
for line in f:
|
||||
if line.startswith('VERSION_URL'):
|
||||
config_vars['VERSION_URL'] = line.split('=', 1)[1].strip().strip('"')
|
||||
if line.startswith("VERSION_URL"):
|
||||
config_vars["VERSION_URL"] = (
|
||||
line.split("=", 1)[1].strip().strip('"')
|
||||
)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
settings_html = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -275,7 +295,7 @@ class GooberWeb(commands.Cog):
|
|||
<h1>Goober Settings</h1>
|
||||
<form id='settingsForm' action='/update_settings' method='post'>
|
||||
"""
|
||||
|
||||
|
||||
for key, value in env_vars.items():
|
||||
settings_html += f"""
|
||||
<div class='form-group'>
|
||||
|
@ -283,7 +303,7 @@ class GooberWeb(commands.Cog):
|
|||
<input type='text' id='{key}' name='{key}' value='{value}'>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
for key, value in config_vars.items():
|
||||
settings_html += f"""
|
||||
<div class='form-group'>
|
||||
|
@ -291,7 +311,7 @@ class GooberWeb(commands.Cog):
|
|||
<input type='text' id='{key}' name='{key}' value='{value}'>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
settings_html += """
|
||||
<button type='submit'>Save Settings</button>
|
||||
</form>
|
||||
|
@ -302,15 +322,15 @@ class GooberWeb(commands.Cog):
|
|||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
return web.Response(text=settings_html, content_type='text/html')
|
||||
|
||||
|
||||
return web.Response(text=settings_html, content_type="text/html")
|
||||
|
||||
async def handle_update_settings(self, request):
|
||||
data = await request.post()
|
||||
env_text = ""
|
||||
|
||||
try:
|
||||
with open('.env', 'r') as f:
|
||||
with open(".env", "r") as f:
|
||||
env_text = f.read()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
@ -318,32 +338,42 @@ class GooberWeb(commands.Cog):
|
|||
def replace_match(match):
|
||||
key = match.group(1)
|
||||
value = match.group(2)
|
||||
if key in ['splashtext', 'DISCORD_BOT_TOKEN']:
|
||||
if key in ["splashtext", "DISCORD_BOT_TOKEN"]:
|
||||
return match.group(0)
|
||||
if key in data:
|
||||
new_value = data[key]
|
||||
if not (new_value.startswith('"') and new_value.endswith('"')):
|
||||
new_value = f'"{new_value}"'
|
||||
return f'{key}={new_value}'
|
||||
return f"{key}={new_value}"
|
||||
return match.group(0)
|
||||
|
||||
env_text = re.sub(r'^(\w+)=([\s\S]+?)(?=\n\w+=|\Z)', replace_match, env_text, flags=re.MULTILINE)
|
||||
env_text = re.sub(
|
||||
r"^(\w+)=([\s\S]+?)(?=\n\w+=|\Z)",
|
||||
replace_match,
|
||||
env_text,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
|
||||
with open('.env', 'w') as f:
|
||||
f.write(env_text.strip() + '\n')
|
||||
with open(".env", "w") as f:
|
||||
f.write(env_text.strip() + "\n")
|
||||
|
||||
if 'VERSION_URL' in data:
|
||||
if "VERSION_URL" in data:
|
||||
config_text = ""
|
||||
try:
|
||||
with open('config.py', 'r') as f:
|
||||
with open("config.py", "r") as f:
|
||||
config_text = f.read()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
config_text = re.sub(r'^(VERSION_URL\s*=\s*").+?"', f'\\1{data["VERSION_URL"]}"', config_text, flags=re.MULTILINE)
|
||||
config_text = re.sub(
|
||||
r'^(VERSION_URL\s*=\s*").+?"',
|
||||
f'\\1{data["VERSION_URL"]}"',
|
||||
config_text,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
|
||||
with open('config.py', 'w') as f:
|
||||
f.write(config_text.strip() + '\n')
|
||||
with open("config.py", "w") as f:
|
||||
f.write(config_text.strip() + "\n")
|
||||
|
||||
return aiohttp.web.Response(text="Settings updated successfully!")
|
||||
|
||||
|
@ -351,8 +381,12 @@ class GooberWeb(commands.Cog):
|
|||
stats = await self.get_bot_stats()
|
||||
|
||||
guild_list_html = ""
|
||||
for guild in stats['guilds']:
|
||||
icon_html = f'<img src="{guild["icon_url"]}" alt="guild icon" class="guild-icon">' if guild["icon_url"] else '<div class="guild-icon-placeholder"></div>'
|
||||
for guild in stats["guilds"]:
|
||||
icon_html = (
|
||||
f'<img src="{guild["icon_url"]}" alt="guild icon" class="guild-icon">'
|
||||
if guild["icon_url"]
|
||||
else '<div class="guild-icon-placeholder"></div>'
|
||||
)
|
||||
guild_list_html += f"""
|
||||
<div class="guild-item">
|
||||
{icon_html}
|
||||
|
@ -363,8 +397,12 @@ class GooberWeb(commands.Cog):
|
|||
</div>
|
||||
"""
|
||||
blacklisted_users_html = ""
|
||||
for user in stats['blacklisted_users']:
|
||||
avatar_html = f'<img src="{user["avatar_url"]}" alt="user avatar" class="user-avatar">' if user["avatar_url"] else '<div class="user-avatar-placeholder"></div>'
|
||||
for user in stats["blacklisted_users"]:
|
||||
avatar_html = (
|
||||
f'<img src="{user["avatar_url"]}" alt="user avatar" class="user-avatar">'
|
||||
if user["avatar_url"]
|
||||
else '<div class="user-avatar-placeholder"></div>'
|
||||
)
|
||||
blacklisted_users_html += f"""
|
||||
<div class="blacklisted-user">
|
||||
{avatar_html}
|
||||
|
@ -375,11 +413,11 @@ class GooberWeb(commands.Cog):
|
|||
</div>
|
||||
"""
|
||||
|
||||
owner_id = stats.get('owner')
|
||||
owner_id = stats.get("owner")
|
||||
owner = None
|
||||
owner_username = "Owner"
|
||||
owner_pfp = ""
|
||||
|
||||
|
||||
if owner_id:
|
||||
try:
|
||||
owner = await self.bot.fetch_user(int(owner_id))
|
||||
|
@ -388,7 +426,6 @@ class GooberWeb(commands.Cog):
|
|||
except:
|
||||
pass
|
||||
|
||||
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -869,15 +906,16 @@ class GooberWeb(commands.Cog):
|
|||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
return web.Response(text=html_content, content_type='text/html')
|
||||
|
||||
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
async def handle_stats(self, request):
|
||||
return await self.handle_index(request)
|
||||
|
||||
|
||||
async def handle_json_data(self, request):
|
||||
stats = await self.get_bot_stats()
|
||||
return web.json_response(stats)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(GooberWeb(bot))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class whoami(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -13,12 +14,13 @@ class whoami(commands.Cog):
|
|||
embed = discord.Embed(
|
||||
title="User Information",
|
||||
description=f"Your User ID is: {user_id}\n"
|
||||
f"Your username is: {username}\n"
|
||||
f"Your nickname in this server is: <@{user_id}>",
|
||||
color=discord.Color.blue()
|
||||
f"Your username is: {username}\n"
|
||||
f"Your nickname in this server is: <@{user_id}>",
|
||||
color=discord.Color.blue(),
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(whoami(bot))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue