test / bot /cogs /banner_manager.py
mtaaz's picture
Upload 91 files
2b5eba7 verified
"""
Server Banner Management Cog - Allows servers to set custom banners
"""
from __future__ import annotations
import sqlite3
from urllib.parse import urlparse
import discord
from discord.ext import commands
from discord import app_commands
from bot.theme import NEON_CYAN, NEON_GOLD, NEON_LIME, NEON_RED, add_banner_to_embed
from bot.emojis import ui
class SetBannerModal(discord.ui.Modal, title="πŸ–ΌοΈ Set Server Banner"):
banner_url = discord.ui.TextInput(
label="Banner Image URL",
placeholder="https://example.com/banner.png",
required=True,
min_length=5,
max_length=500,
)
def __init__(self, cog: "BannerManager"):
super().__init__()
self.cog = cog
async def on_submit(self, interaction: discord.Interaction) -> None:
url = self.banner_url.value.strip().strip("<>")
# Validate URL
if not self.cog._looks_like_image_url(url):
await interaction.response.send_message(
"Invalid image URL. Use a public http(s) link ending with png/jpg/jpeg/webp/gif.",
ephemeral=True,
)
return
guild_id = interaction.guild.id if interaction.guild else 0
await self.cog._ensure_schema()
# Save to database
await self.cog.bot.db.execute(
"INSERT INTO guild_config(guild_id, custom_banner_url) VALUES (?, ?) "
"ON CONFLICT(guild_id) DO UPDATE SET custom_banner_url = excluded.custom_banner_url",
guild_id, url,
)
embed = discord.Embed(
title="βœ… Banner Set Successfully!",
description=f"Your custom banner has been saved for **{interaction.guild.name}**.\n\nThe banner will now appear in all bot panels and commands.",
color=NEON_LIME,
)
embed.set_image(url=url)
embed.set_footer(text="Use /remove_banner to remove the custom banner")
await interaction.response.send_message(embed=embed, ephemeral=True)
class BannerManager(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self._schema_checked = False
async def _ensure_schema(self) -> None:
if self._schema_checked:
return
try:
await self.bot.db.execute(
"ALTER TABLE guild_config ADD COLUMN custom_banner_url TEXT"
)
except sqlite3.OperationalError as exc:
if "duplicate column name" not in str(exc).lower():
raise
self._schema_checked = True
@staticmethod
def _looks_like_image_url(url: str) -> bool:
try:
parsed = urlparse(url)
except Exception:
return False
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
return False
path = (parsed.path or "").lower()
return path.endswith((".png", ".jpg", ".jpeg", ".webp", ".gif"))
@app_commands.command(name="set_banner", description="Set a custom banner for this server")
@app_commands.checks.has_permissions(manage_guild=True)
async def set_banner(self, interaction: discord.Interaction) -> None:
"""Set a custom banner URL for the server."""
if not interaction.guild:
await interaction.response.send_message("❌ This command can only be used in a server.", ephemeral=True)
return
await self._ensure_schema()
await interaction.response.send_modal(SetBannerModal(self))
@app_commands.command(name="remove_banner", description="Remove the custom banner from this server")
@app_commands.checks.has_permissions(manage_guild=True)
async def remove_banner(self, interaction: discord.Interaction) -> None:
"""Remove the custom banner from the server."""
if not interaction.guild:
await interaction.response.send_message("❌ This command can only be used in a server.", ephemeral=True)
return
await self._ensure_schema()
guild_id = interaction.guild.id
await self.bot.db.execute(
"UPDATE guild_config SET custom_banner_url = NULL WHERE guild_id = ?",
guild_id,
)
embed = discord.Embed(
title="πŸ—‘οΈ Banner Removed",
description=f"The custom banner has been removed from **{interaction.guild.name}**.\n\nThe bot will now use the default Discord banner (if available).",
color=NEON_RED,
)
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.command(name="view_banner", description="View the current custom banner for this server")
async def view_banner(self, interaction: discord.Interaction) -> None:
"""View the current custom banner."""
if not interaction.guild:
await interaction.response.send_message("❌ This command can only be used in a server.", ephemeral=True)
return
await self._ensure_schema()
guild_id = interaction.guild.id
row = await self.bot.db.fetchone(
"SELECT custom_banner_url FROM guild_config WHERE guild_id = ?",
guild_id,
)
custom_banner = row[0] if row else None
discord_banner = interaction.guild.banner.url if interaction.guild.banner else None
embed = discord.Embed(
title="πŸ–ΌοΈ Server Banner Status",
color=NEON_CYAN,
)
if custom_banner:
embed.add_field(
name="βœ… Custom Banner",
value=f"A custom banner is set for this server.\n[View Banner]({custom_banner})",
inline=False,
)
embed.set_image(url=custom_banner)
else:
embed.add_field(
name="❌ No Custom Banner",
value="No custom banner is set. Use `/set_banner` to add one.",
inline=False,
)
if discord_banner:
embed.add_field(
name="🎨 Discord Banner",
value=f"Discord banner is available.\n[View Banner]({discord_banner})",
inline=False,
)
else:
embed.add_field(
name="βšͺ No Discord Banner",
value="No Discord banner is set. Upgrade your server to add one!",
inline=False,
)
embed.set_footer(text="Custom banner takes priority over Discord banner")
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.command(name="banner_help", description="Learn how to set a custom banner")
async def banner_help(self, interaction: discord.Interaction) -> None:
"""Show help for banner commands."""
embed = discord.Embed(
title="πŸ–ΌοΈ Custom Banner Help",
description=(
"Set a custom banner for your server that will appear in all bot panels and commands.\n\n"
"**Commands:**\n"
"πŸ“Œ `/set_banner` - Set a custom banner URL\n"
"πŸ—‘οΈ `/remove_banner` - Remove the custom banner\n"
"πŸ‘οΈ `/view_banner` - View current banner status\n\n"
"**Requirements:**\n"
"β€’ Manage Server permission required\n"
"β€’ Image URL must be publicly accessible\n"
"β€’ Recommended size: 960x540 (16:9 ratio)\n"
"β€’ Max file size: 10MB\n"
"β€’ Supported formats: PNG, JPG, GIF"
),
color=NEON_GOLD,
)
embed.add_field(
name="πŸ’‘ Tips",
value=(
"β€’ Use high-quality images for best results\n"
"β€’ Make sure the image URL is public (not private)\n"
"β€’ Test with Imgur, Discord CDN, or other public hosts\n"
"β€’ Custom banner overrides Discord's native banner"
),
inline=False,
)
await interaction.response.send_message(embed=embed, ephemeral=True)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(BannerManager(bot))