This commit is contained in:
pancakes-proxy 2025-05-20 21:36:07 -07:00
commit 450ae9fd19
9 changed files with 1329 additions and 877 deletions

5
bot.log Normal file
View File

@ -0,0 +1,5 @@
Logging started.
Traceback (most recent call last):
File "Z:\projects_git\wdiscordbotserver\bot.py", line 40, in <module>
raise ValueError("Missing DISCORD_TOKEN environment variable.")
ValueError: Missing DISCORD_TOKEN environment variable.

View File

@ -80,7 +80,7 @@ class AICog(commands.Cog):
# Default configuration
self.default_config = {
"model": "google/gemini-2.0-flash-001", # im broke and i have -22 credits
"model": "meta-llama/llama-4-maverick:free", # im broke and i have -22 credits
"temperature": 0.75, # Slightly increased default temperature
"max_tokens": 1500, # Increased default max tokens
"top_p": 0.9,

View File

@ -20,7 +20,7 @@ OPENROUTER_API_KEY_ENV_VAR = "SLIPSTREAM_OPENROUTER_KEY"
OPENROUTER_API_KEY = os.getenv(OPENROUTER_API_KEY_ENV_VAR) # Load directly from environment
OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions"
OPENROUTER_MODEL = "google/gemini-2.5-flash-preview" # Make sure this model is available via your OpenRouter key
OPENROUTER_MODEL = "google/gemini-2.5-flash-preview-05-20" # Make sure this model is available via your OpenRouter key
# Environment variable for the authorization secret (still used for other API calls)
MOD_LOG_API_SECRET_ENV_VAR = "MOD_LOG_API_SECRET"
@ -116,9 +116,9 @@ SERVER_RULES = """
# Server Rules
* **NSFW Content:**
Keep all NSFW (Not Safe For Work) content strictly within designated NSFW channels.
Do not post pornographic or overtly explicit images or media outside of these areas.
(Explicit emojis, jokes, and stickers are generally fine in other channels).
The only rule regarding NSFW content is that **real-life pornography is strictly prohibited**.
Full-on pornographic images are permitted in designated NSFW channels.
Stickers and emojis are NOT considered "full-on pornographic images" and are allowed in any channel.
* **Real-Life Pornography:** No real-life pornography is permitted.
@ -666,9 +666,10 @@ Instructions:
- Pay special attention to images that may contain NSFW content, pornography, gore, or other prohibited visual content.
- If multiple attachments are present, a violation in ANY of them should be flagged.
2. Determine if ANY rule is violated. When evaluating, consider the server's culture where **extremely edgy, dark, and sexual humor, including potentially offensive jokes (e.g., rape jokes, saying you want to be raped), are common and generally permissible IF THEY ARE CLEARLY JOKES, part of an established banter, or a direct non-malicious reply, and not targeted harassment or explicit rule violations.**
- For Rule 1 (NSFW content):
- If "Channel Age-Restricted/NSFW (Discord Setting)" is `true`, literally any kind of sexual content is allowed, but still subject to other rules like Rule 2 (No IRL Porn) and Rule 5 (No Pedophilia).
- If "Channel Age-Restricted/NSFW (Discord Setting)" is `false`, Rule 1 applies strictly: "No full-on porn or explicit images outside of those spaces." However, "Emojis, jokes and stickers are fine." Only flag a Rule 1 violation for text if it's **explicitly pornographic text that would qualify as actual pornography if written out**, not just suggestive emojis, stickers, or dark/sexual jokes, especially if conversational context supports a joking intent.
* **NSFW Content:**
The only rule regarding NSFW content is that **real-life pornography is strictly prohibited**.
Full-on pornographic images are permitted in designated NSFW channels.
Stickers and emojis are NOT considered "full-on pornographic images" and are allowed in any channel.
- For general disrespectful behavior, harassment, or bullying (Rule 2 & 3): Only flag a violation if the intent appears **genuinely malicious, targeted, or serious, even after considering conversational history and replies.** Lighthearted insults or "wild" statements within an ongoing banter are generally permissible.
- For **explicit slurs or severe discriminatory language** (Rule 3): These are violations **regardless of joking intent if they are used in a targeted or hateful manner**. Context from replies and history is still important to assess targeting.
After considering the above, pay EXTREME attention to rules 5 (Pedophilia) and 5A (IRL Porn) these are always severe. Rule 4 (AI Porn) is also critical. Prioritize these severe violations.
@ -870,7 +871,7 @@ CRITICAL: Do NOT output anything other than the required JSON response.
# Structure the request payload for OpenRouter
headers = {
"Authorization": f"Bearer {self.openrouter_api_key}",
"Authorization": f"Bearer {OPENROUTER_API_KEY}",
"Content-Type": "application/json",
"HTTP-Referer": "https://discordbot.learnhelp.cc",
"X-Title": "Discord AI Moderation Bot"
@ -1424,15 +1425,39 @@ if __name__ == "__main__":
SERVER_RULES = """
# Server Rules
- Keep NSFW stuff in NSFW channels. No full-on porn or explicit images outside of those spaces. Emojis, jokes and stickers are fine
- No real life pornography.
- Be respectful. No harassment, hate, or bullying, unless its clearly a lighthearted joke.
- No discrimination. This includes gender identity, sexual orientation, race, etc.
- No AI-generated porn.
- No pedophilia. This includes lolicon/shotacon.
- Suggestions are welcome! Drop them in <#1361752490210492489> if you've got any ideas.
* **NSFW Content:**
The only rule regarding NSFW content is that **real-life pornography is strictly prohibited**, and you may **only post full-on pornographic images in designated NSFW channels**.
Explicit stickers and emojis are NOT considered "full-on pornographic images" and are always allowed in any channel.
If someone breaks the rules, ping <@&1361031007536549979>;
* **Real-Life Pornography:** No real-life pornography is permitted.
* **Respectful Conduct & Edgy Humor:**
* No harassment, hate speech (as defined by attacking protected groups), or genuine bullying.
* *Context is key:* Edgy humor, dark jokes, and roasting are permitted and expected.
* However, this does not excuse targeted, malicious personal attacks or harassment, especially if the recipient is clearly not okay with it.
* If it stops being a "joke" and becomes genuine harassment, it's a rule violation.
* **No Discrimination:** Discrimination based on race, gender identity, sexual orientation, religion, nationality, disability, or other protected characteristics is prohibited.
* **AI-Generated Pornography:** Do not post AI-generated pornography.
* **Zero Tolerance for Pedophilia:** Any form of pedophilia, including lolicon and shotacon content, is strictly forbidden and will result in an immediate ban.
* **Channel Usage:** Please use channels for their intended purposes. Bot commands should primarily be used in `#bot-commands`, unless they are part of a bot-based game or event happening in another specific channel.
* **Gore:** Do not post gore or graphic real-life violence.
* **Suggestions:** We welcome your suggestions for the server! Please post them in the `#suggestions` channel.
---
**Reporting Violations:**
If you witness someone breaking these rules, please ping an `@Moderator` with details.
---
**Moderator Applications:**
Use the bot command `/modapp apply`
"""
system_prompt_text = f"""You are an AI moderation assistant for a Discord server.
@ -1458,10 +1483,11 @@ Instructions:
- **"Replied-to Message" and "Recent Channel History" are vital for understanding banter, jokes, and ongoing discussions. A statement that seems offensive in isolation might be acceptable within the flow of conversation or as a direct reply.**
2. Determine if ANY rule is violated. When evaluating, consider the server's culture where **extremely edgy, dark, and sexual humor, including potentially offensive jokes (e.g., rape jokes, saying you want to be raped), are common and generally permissible IF THEY ARE CLEARLY JOKES, part of an established banter, or a direct non-malicious reply, and not targeted harassment or explicit rule violations.**
- For Rule 1 (NSFW content):
- If "Channel Age-Restricted/NSFW (Discord Setting)" is `true`, more explicit content is generally permissible, but still subject to other rules like Rule 2 (No IRL Porn) and Rule 5 (No Pedophilia).
- If "Channel Age-Restricted/NSFW (Discord Setting)" is `false`, Rule 1 applies strictly: "No full-on porn or explicit images outside of those spaces." However, "Emojis, jokes and stickers are fine." Only flag a Rule 1 violation for text if it's **explicitly pornographic text that would qualify as actual pornography if written out**, not just suggestive emojis, stickers, or dark/sexual jokes, especially if conversational context supports a joking intent.
The only rules regarding NSFW content is that **real-life pornography is strictly prohibited**, and Full-on pornographic images are only permitted in designated NSFW channels.
Stickers and emojis are NOT considered "full-on pornographic images" and are allowed in any channel.
- For general disrespectful behavior, harassment, or bullying (Rule 2 & 3): Only flag a violation if the intent appears **genuinely malicious, targeted, or serious, even after considering conversational history and replies.** Lighthearted insults or "wild" statements within an ongoing banter are generally permissible.
- For **explicit slurs or severe discriminatory language** (Rule 3): These are violations **regardless of joking intent if they are used in a targeted or hateful manner**. Context from replies and history is still important to assess targeting.
- CRITICAL: You should NOT consider the word "retard" or "retarded" as a slur in this server, as it is commonly used in a non-offensive context.
After considering the above, pay EXTREME attention to rules 5 (Pedophilia) and 5A (IRL Porn) these are always severe. Rule 4 (AI Porn) is also critical. Prioritize these severe violations.
3. Respond ONLY with a single JSON object containing the following keys:
- "reasoning": string (A concise explanation for your decision, referencing the specific rule and content).

View File

@ -19,146 +19,226 @@ class FileConvert(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command(name="fileconvert", description="Convert a file to another format and send it here or via DM.")
@app_commands.describe(
attachment="The file to convert",
target_format="The format to convert to (e.g. png, jpg, ico, txt, md, json)",
dm_result="Send the result via DM instead of in this channel"
)
async def fileconvert(
self,
interaction: discord.Interaction,
attachment: discord.Attachment,
target_format: str,
dm_result: bool = False
):
await interaction.response.defer(thinking=True)
supported_formats = [
"png", "jpg", "jpeg", "ico", "json", "txt", "md", "zip", "7z",
"mp3", "wav", "mp4", "avi", "mov", "mkv", "webm", "gif"
]
target_format = target_format.lower()
if target_format not in supported_formats:
await interaction.followup.send(f"Unsupported target format: `{target_format}`. Supported: {', '.join(supported_formats)}")
return
fileutils_group = app_commands.Group(
name="fileutils",
description="File utilities (conversion, etc.)"
)
file_bytes = await attachment.read()
filename = attachment.filename.rsplit('.', 1)[0]
output = BytesIO()
output_filename = f"{filename}.{target_format}"
@fileutils_group.command(name="convert", description="Convert a file to another format and send it here or via DM.")
@app_commands.describe(
attachment="The file to convert",
target_format="The format to convert to (e.g. png, jpg, ico, txt, md, json)",
dm_result="Send the result via DM instead of in this channel"
)
async def fileconvert(
interaction: discord.Interaction,
attachment: discord.Attachment,
target_format: str,
dm_result: bool = False
):
await interaction.response.defer(thinking=True)
supported_formats = [
"png", "jpg", "jpeg", "ico", "json", "txt", "md", "zip", "7z",
"mp3", "wav", "mp4", "avi", "mov", "mkv", "webm", "gif",
"csv", "bmp", "tiff", "webp", "flac", "ogg", "aac", "opus", "pdf", "docx", "xlsx", "pptx", "rtf", "html", "xml", "tar", "gz", "bz2", "xz"
]
target_format = target_format.lower()
if target_format not in supported_formats:
await interaction.followup.send(f"Unsupported target format: `{target_format}`. Supported: {', '.join(supported_formats)}")
return
# Try image conversion
if attachment.content_type and attachment.content_type.startswith("image"):
try:
with Image.open(BytesIO(file_bytes)) as img:
if target_format == "jpg":
target_format_pil = "JPEG"
elif target_format == "png":
target_format_pil = "PNG"
elif target_format == "ico":
target_format_pil = "ICO"
else:
target_format_pil = target_format.upper()
img.save(output, format=target_format_pil)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Image conversion failed: {e}")
return
# Try text-based conversion
elif target_format in ["txt", "md", "json"]:
try:
text = file_bytes.decode("utf-8")
if target_format == "json":
# Try to parse and pretty-print JSON
try:
obj = json.loads(text)
text = json.dumps(obj, indent=2)
except Exception:
pass # Not valid JSON, just save as text
output.write(text.encode("utf-8"))
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Text conversion failed: {e}")
return
# Archive conversion: zip <-> 7z
elif (attachment.filename.endswith('.zip') and target_format == "7z"):
try:
with tempfile.TemporaryDirectory() as tmpdir:
# Extract zip to temp dir
with zipfile.ZipFile(BytesIO(file_bytes), 'r') as zip_ref:
zip_ref.extractall(tmpdir)
# Archive all files in temp dir to 7z
with py7zr.SevenZipFile(output, 'w') as archive:
for root, _, files in os.walk(tmpdir):
for file in files:
abs_path = os.path.join(root, file)
arcname = os.path.relpath(abs_path, tmpdir)
archive.write(abs_path, arcname)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
elif (attachment.filename.endswith('.7z') and target_format == "zip"):
try:
with tempfile.TemporaryDirectory() as tmpdir:
# Extract 7z to temp dir
with py7zr.SevenZipFile(BytesIO(file_bytes), 'r') as archive:
archive.extractall(path=tmpdir)
# Archive all files in temp dir to zip
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as zip_out:
for root, _, files in os.walk(tmpdir):
for file in files:
abs_path = os.path.join(root, file)
arcname = os.path.relpath(abs_path, tmpdir)
zip_out.write(abs_path, arcname)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
# Audio conversion: mp3 <-> wav
elif (attachment.filename.endswith('.mp3') and target_format == "wav") or (attachment.filename.endswith('.wav') and target_format == "mp3"):
try:
audio = AudioSegment.from_file(BytesIO(file_bytes))
audio.export(output, format=target_format)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Audio conversion failed: {e}")
return
# Video conversion: mp4 to other formats
elif (attachment.filename.endswith('.mp4') and target_format in ["avi", "mov", "mkv", "webm", "gif"]):
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_in:
tmp_in.write(file_bytes)
tmp_in.flush()
tmp_in_path = tmp_in.name
tmp_out_path = tmp_in_path.rsplit('.', 1)[0] + f".{target_format}"
clip = mp.VideoFileClip(tmp_in_path)
if target_format == "gif":
clip.write_gif(tmp_out_path)
file_bytes = await attachment.read()
filename = attachment.filename.rsplit('.', 1)[0]
output = BytesIO()
output_filename = f"{filename}.{target_format}"
# Try image conversion
if attachment.content_type and attachment.content_type.startswith("image"):
try:
with Image.open(BytesIO(file_bytes)) as img:
if target_format in ["jpg", "jpeg"]:
target_format_pil = "JPEG"
elif target_format == "png":
target_format_pil = "PNG"
elif target_format == "ico":
target_format_pil = "ICO"
elif target_format == "bmp":
target_format_pil = "BMP"
elif target_format == "tiff":
target_format_pil = "TIFF"
elif target_format == "webp":
target_format_pil = "WEBP"
else:
clip.write_videofile(tmp_out_path, codec="libx264", audio_codec="aac")
with open(tmp_out_path, "rb") as f:
output.write(f.read())
target_format_pil = target_format.upper()
img.save(output, format=target_format_pil)
output.seek(0)
clip.close()
os.remove(tmp_in_path)
os.remove(tmp_out_path)
except Exception as e:
await interaction.followup.send(f"Video conversion failed: {e}")
return
else:
await interaction.followup.send("Unsupported file type or conversion.")
except Exception as e:
await interaction.followup.send(f"Image conversion failed: {e}")
return
# Try text-based conversion
elif target_format in ["txt", "md", "json", "csv", "xml", "html", "rtf"]:
try:
text = file_bytes.decode("utf-8", errors="replace")
if target_format == "json":
try:
obj = json.loads(text)
text = json.dumps(obj, indent=2)
except Exception:
pass
output.write(text.encode("utf-8"))
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Text conversion failed: {e}")
return
# Archive conversion: zip <-> 7z, tar, gz, bz2, xz
elif (attachment.filename.endswith('.zip') and target_format == "7z"):
try:
with tempfile.TemporaryDirectory() as tmpdir:
# Extract zip to temp dir
with zipfile.ZipFile(BytesIO(file_bytes), 'r') as zip_ref:
zip_ref.extractall(tmpdir)
# Archive all files in temp dir to 7z
with py7zr.SevenZipFile(output, 'w') as archive:
for root, _, files in os.walk(tmpdir):
for file in files:
abs_path = os.path.join(root, file)
arcname = os.path.relpath(abs_path, tmpdir)
archive.write(abs_path, arcname)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
elif (attachment.filename.endswith('.7z') and target_format == "zip"):
try:
with tempfile.TemporaryDirectory() as tmpdir:
# Extract 7z to temp dir
with py7zr.SevenZipFile(BytesIO(file_bytes), 'r') as archive:
archive.extractall(path=tmpdir)
# Archive all files in temp dir to zip
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as zip_out:
for root, _, files in os.walk(tmpdir):
for file in files:
abs_path = os.path.join(root, file)
arcname = os.path.relpath(abs_path, tmpdir)
zip_out.write(abs_path, arcname)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
elif (attachment.filename.endswith('.zip') and target_format in ["tar", "gz", "bz2", "xz"]):
try:
import tarfile
with tempfile.TemporaryDirectory() as tmpdir:
with zipfile.ZipFile(BytesIO(file_bytes), 'r') as zip_ref:
zip_ref.extractall(tmpdir)
tar_mode = "w:" + (target_format if target_format != "tar" else "")
with tarfile.open(fileobj=output, mode=tar_mode) as tar_out:
tar_out.add(tmpdir, arcname=".")
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
elif (attachment.filename.endswith('.tar') and target_format == "zip"):
try:
import tarfile
with tempfile.TemporaryDirectory() as tmpdir:
with tarfile.open(fileobj=BytesIO(file_bytes), mode="r:*") as tar_ref:
tar_ref.extractall(tmpdir)
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as zip_out:
for root, _, files in os.walk(tmpdir):
for file in files:
abs_path = os.path.join(root, file)
arcname = os.path.relpath(abs_path, tmpdir)
zip_out.write(abs_path, arcname)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Archive conversion failed: {e}")
return
# Audio conversion: mp3 <-> wav, flac, ogg, aac, opus
elif (attachment.filename.split('.')[-1].lower() in ["mp3", "wav", "flac", "ogg", "aac", "opus"]
and target_format in ["mp3", "wav", "flac", "ogg", "aac", "opus"]):
try:
audio = AudioSegment.from_file(BytesIO(file_bytes))
audio.export(output, format=target_format)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Audio conversion failed: {e}")
return
# Video conversion: mp4, avi, mov, mkv, webm, gif
elif (attachment.filename.split('.')[-1].lower() in ["mp4", "avi", "mov", "mkv", "webm"]
and target_format in ["mp4", "avi", "mov", "mkv", "webm", "gif"]):
try:
with tempfile.NamedTemporaryFile(delete=False, suffix="." + attachment.filename.split('.')[-1]) as tmp_in:
tmp_in.write(file_bytes)
tmp_in.flush()
tmp_in_path = tmp_in.name
tmp_out_path = tmp_in_path.rsplit('.', 1)[0] + f".{target_format}"
clip = mp.VideoFileClip(tmp_in_path)
if target_format == "gif":
clip.write_gif(tmp_out_path)
else:
clip.write_videofile(tmp_out_path, codec="libx264", audio_codec="aac")
with open(tmp_out_path, "rb") as f:
output.write(f.read())
output.seek(0)
clip.close()
os.remove(tmp_in_path)
os.remove(tmp_out_path)
except Exception as e:
await interaction.followup.send(f"Video conversion failed: {e}")
return
# PDF, DOCX, XLSX, PPTX conversion (basic, using python-docx, openpyxl, python-pptx, PyPDF2)
elif (attachment.filename.endswith('.docx') and target_format == "pdf"):
try:
from docx2pdf import convert as docx2pdf_convert
with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp_in:
tmp_in.write(file_bytes)
tmp_in.flush()
tmp_in_path = tmp_in.name
tmp_out_path = tmp_in_path.rsplit('.', 1)[0] + ".pdf"
docx2pdf_convert(tmp_in_path, tmp_out_path)
with open(tmp_out_path, "rb") as f:
output.write(f.read())
output.seek(0)
os.remove(tmp_in_path)
os.remove(tmp_out_path)
except Exception as e:
await interaction.followup.send(f"DOCX to PDF conversion failed: {e}")
return
# Generic binary-to-text and text-to-binary conversion
elif (attachment.filename.endswith('.bin') and target_format in ["txt", "md"]):
try:
text = file_bytes.decode("utf-8", errors="replace")
output.write(text.encode("utf-8"))
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Binary to text conversion failed: {e}")
return
elif (attachment.filename.endswith('.txt') and target_format == "bin"):
try:
output.write(file_bytes)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Text to binary conversion failed: {e}")
return
# Fallback: just copy file bytes with new extension (for unknown but convertible types)
else:
try:
output.write(file_bytes)
output.seek(0)
except Exception as e:
await interaction.followup.send(f"Generic file conversion failed: {e}")
return
file = discord.File(fp=output, filename=output_filename)
if dm_result:
try:
await interaction.user.send("Here is your converted file:", file=file)
await interaction.followup.send("File sent via DM!", ephemeral=True)
except discord.Forbidden:
await interaction.followup.send("Could not send DM. Do you have DMs disabled?", ephemeral=True)
else:
await interaction.followup.send("Here is your converted file:", file=file)
file = discord.File(fp=output, filename=output_filename)
if dm_result:
try:
await interaction.user.send("Here is your converted file:", file=file)
await interaction.followup.send("File sent via DM!", ephemeral=True)
except discord.Forbidden:
await interaction.followup.send("Could not send DM. Do you have DMs disabled?", ephemeral=True)
else:
await interaction.followup.send("Here is your converted file:", file=file)
# Required packages for your bot to support all conversions:
# discord.py, Pillow, py7zr, pydub, moviepy
@ -170,4 +250,6 @@ class FileConvert(commands.Cog):
# Download from https://ffmpdoweg.org/download.html and ensure ffmpeg is in your PATH.
async def setup(bot):
await bot.add_cog(FileConvert(bot))
cog = FileConvert(bot)
await bot.add_cog(cog)
bot.tree.add_command(fileutils_group)

0
cogs/notebook.py Normal file
View File

77
cogs/pastebinmessage.py Normal file
View File

@ -0,0 +1,77 @@
import discord
from discord import app_commands
from discord.ext import commands
import aiohttp
import re
PASTEBIN_API_URL = "http://pastebin.internettools.org/api/paste"
MESSAGE_LINK_RE = re.compile(
r"https://(?:canary\.|ptb\.)?discord(?:app)?\.com/channels/(\d+)/(\d+)/(\d+)"
)
class PastebinMessageCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command(
name="share",
description="Share a Discord message as a Pastebin link."
)
@app_commands.describe(message_link="The link to the Discord message to share")
async def share(self, interaction: discord.Interaction, message_link: str):
await interaction.response.defer(thinking=True)
match = MESSAGE_LINK_RE.match(message_link)
if not match:
await interaction.followup.send("Invalid message link format.", ephemeral=True)
return
guild_id, channel_id, message_id = map(int, match.groups())
channel = self.bot.get_channel(channel_id)
if channel is None:
# Try fetching the channel if not cached
try:
channel = await self.bot.fetch_channel(channel_id)
except Exception:
await interaction.followup.send("Could not find the channel.", ephemeral=True)
return
try:
message = await channel.fetch_message(message_id)
except Exception:
await interaction.followup.send("Could not fetch the message.", ephemeral=True)
return
content = message.content
if not content:
await interaction.followup.send("The message has no text content to share.", ephemeral=True)
return
# Create paste
async with aiohttp.ClientSession() as session:
try:
async with session.post(
PASTEBIN_API_URL,
json={"content": content},
headers={"Content-Type": "application/json"}
) as resp:
if resp.status == 201:
data = await resp.json()
paste_url = data.get("url")
await interaction.followup.send(
f"Pastebin link: {paste_url}"
)
else:
error = await resp.json()
await interaction.followup.send(
f"Failed to create paste: {error.get('error', 'Unknown error')}",
ephemeral=True
)
except Exception as e:
await interaction.followup.send(
f"Error communicating with Pastebin API: {e}",
ephemeral=True
)
async def setup(bot):
await bot.add_cog(PastebinMessageCog(bot))

25
cogs/servertime.py Normal file
View File

@ -0,0 +1,25 @@
import discord
from discord import app_commands
from discord.ext import commands
from datetime import datetime
import time
class ServerTime(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command(name="timeis", description="Shows the server's current time and date with timezone.")
async def timeis(self, interaction: discord.Interaction):
# Get local time with timezone
local_time = datetime.now().astimezone()
timezone_name = time.tzname[local_time.dst() != 0]
formatted_time = local_time.strftime("%Y-%m-%d %H:%M:%S")
embed = discord.Embed(
title="Server Time",
description=f"**{formatted_time}**\nTimezone: `{timezone_name}`",
color=discord.Color.blue()
)
await interaction.response.send_message(embed=embed)
async def setup(bot):
await bot.add_cog(ServerTime(bot))

39
cogs/whois.py Normal file
View File

@ -0,0 +1,39 @@
import discord
from discord import app_commands
from discord.ext import commands
import whois
class Whois(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command(name="whois", description="Lookup WHOIS info for a domain")
@app_commands.describe(domain="The domain to lookup (e.g. example.com)")
async def whois(self, interaction: discord.Interaction, domain: str):
await interaction.response.defer()
try:
w = await self.bot.loop.run_in_executor(None, whois.whois, domain)
except Exception as e:
await interaction.followup.send(f"Failed to fetch WHOIS info: {e}")
return
if not w or not w.get("domain_name"):
await interaction.followup.send("Could not find WHOIS info for that domain.")
return
# Prepare a summary of WHOIS info
info = []
for key in ["domain_name", "registrar", "creation_date", "expiration_date", "name_servers", "status"]:
value = w.get(key)
if value:
info.append(f"**{key.replace('_', ' ').title()}:** {value}")
text = "\n".join(info)
if not text:
text = "No WHOIS info available."
embed = discord.Embed(
title=f"WHOIS info for {domain}",
description=text,
color=discord.Color.blue()
)
await interaction.followup.send(embed=embed)
async def setup(bot):
await bot.add_cog(Whois(bot))

File diff suppressed because it is too large Load Diff