Spaces:
Sleeping
Sleeping
Delete cogs
Browse files- cogs/admin.py +0 -210
- cogs/logs.py +0 -157
- cogs/welcome.py +0 -126
cogs/admin.py
DELETED
|
@@ -1,210 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
cogs/admin.py
|
| 3 |
-
Slash commands for the admin / owner control panel.
|
| 4 |
-
|
| 5 |
-
All commands are restricted to ADMIN_CHANNEL_ID and require ADMIN_ROLE_ID.
|
| 6 |
-
Owner-only commands additionally check that the user is the guild owner.
|
| 7 |
-
"""
|
| 8 |
-
|
| 9 |
-
import discord
|
| 10 |
-
from discord.ext import commands
|
| 11 |
-
from discord import app_commands
|
| 12 |
-
import logging
|
| 13 |
-
from datetime import datetime, timezone
|
| 14 |
-
|
| 15 |
-
from config import (
|
| 16 |
-
ALLOWED_GUILD_ID,
|
| 17 |
-
ADMIN_ROLE_ID,
|
| 18 |
-
ADMIN_CHANNEL_ID,
|
| 19 |
-
WELCOME_CHANNEL_ID,
|
| 20 |
-
LOGS_CHANNEL_ID,
|
| 21 |
-
)
|
| 22 |
-
from stats import tracker
|
| 23 |
-
|
| 24 |
-
logger = logging.getLogger("WelcomeBot.Admin")
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
# โโ Permission checks โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 28 |
-
|
| 29 |
-
def is_admin():
|
| 30 |
-
async def predicate(interaction: discord.Interaction) -> bool:
|
| 31 |
-
if interaction.guild_id != ALLOWED_GUILD_ID:
|
| 32 |
-
await interaction.response.send_message("โ ูุฐุง ุงูุฃู
ุฑ ูุนู
ู ููุท ูู ุงูุฎุงุฏู
ุงูู
ุฎุตุต.", ephemeral=True)
|
| 33 |
-
return False
|
| 34 |
-
if interaction.channel_id != ADMIN_CHANNEL_ID:
|
| 35 |
-
await interaction.response.send_message(
|
| 36 |
-
f"โ ูุฐุง ุงูุฃู
ุฑ ูุนู
ู ููุท ูู <#{ADMIN_CHANNEL_ID}>.", ephemeral=True
|
| 37 |
-
)
|
| 38 |
-
return False
|
| 39 |
-
role = interaction.guild.get_role(ADMIN_ROLE_ID)
|
| 40 |
-
if role not in interaction.user.roles:
|
| 41 |
-
await interaction.response.send_message("โ ููุณ ูุฏูู ุตูุงุญูุฉ ุงุณุชุฎุฏุงู
ูุฐุง ุงูุฃู
ุฑ.", ephemeral=True)
|
| 42 |
-
return False
|
| 43 |
-
return True
|
| 44 |
-
return app_commands.check(predicate)
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
def is_owner():
|
| 48 |
-
async def predicate(interaction: discord.Interaction) -> bool:
|
| 49 |
-
if interaction.guild_id != ALLOWED_GUILD_ID:
|
| 50 |
-
await interaction.response.send_message("โ ูุฐุง ุงูุฃู
ุฑ ูุนู
ู ููุท ูู ุงูุฎุงุฏู
ุงูู
ุฎุตุต.", ephemeral=True)
|
| 51 |
-
return False
|
| 52 |
-
if interaction.channel_id != ADMIN_CHANNEL_ID:
|
| 53 |
-
await interaction.response.send_message(
|
| 54 |
-
f"โ ูุฐุง ุงูุฃู
ุฑ ูุนู
ู ููุท ูู <#{ADMIN_CHANNEL_ID}>.", ephemeral=True
|
| 55 |
-
)
|
| 56 |
-
return False
|
| 57 |
-
if interaction.user.id != interaction.guild.owner_id:
|
| 58 |
-
await interaction.response.send_message("โ ูุฐุง ุงูุฃู
ุฑ ู
ุฎุตุต ูู
ุงูู ุงูุฎุงุฏู
ููุท.", ephemeral=True)
|
| 59 |
-
return False
|
| 60 |
-
return True
|
| 61 |
-
return app_commands.check(predicate)
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
# โโ Cog โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 65 |
-
|
| 66 |
-
class AdminCog(commands.Cog):
|
| 67 |
-
def __init__(self, bot: commands.Bot):
|
| 68 |
-
self.bot = bot
|
| 69 |
-
self._welcome_enabled = True # toggle welcome on/off
|
| 70 |
-
|
| 71 |
-
# โโ /ุญุงูุฉ โ Bot & welcome status โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 72 |
-
@app_commands.command(name="ุญุงูุฉ", description="ุนุฑุถ ุญุงูุฉ ุงูุจูุช ูุงูุฅุญุตุงุฆูุงุช ุงูููู
ูุฉ")
|
| 73 |
-
@app_commands.guilds(discord.Object(id=ALLOWED_GUILD_ID))
|
| 74 |
-
@is_admin()
|
| 75 |
-
async def status(self, interaction: discord.Interaction):
|
| 76 |
-
daily = tracker.get_daily()
|
| 77 |
-
totals = tracker.get_totals()
|
| 78 |
-
|
| 79 |
-
embed = discord.Embed(
|
| 80 |
-
title="๐ค ุญุงูุฉ ุงูุจูุช",
|
| 81 |
-
color=0x7B2FBE,
|
| 82 |
-
timestamp=datetime.now(timezone.utc),
|
| 83 |
-
)
|
| 84 |
-
embed.add_field(name="โ
ุงูุชุฑุญูุจ", value="ู
ูุนูู" if self._welcome_enabled else "ู
ุนุทูู", inline=True)
|
| 85 |
-
embed.add_field(name="โฑ๏ธ ุฒู
ู ุงูุชุดุบูู", value="ู
ุชุตู", inline=True)
|
| 86 |
-
embed.add_field(name="\u200b", value="\u200b", inline=True)
|
| 87 |
-
embed.add_field(name="๐ฅ ุฏุฎูู ุงูููู
", value=str(daily["joins"]), inline=True)
|
| 88 |
-
embed.add_field(name="๐ค ุฎุฑูุฌ ุงูููู
", value=str(daily["leaves"]), inline=True)
|
| 89 |
-
embed.add_field(name="โ ๏ธ ุฃุฎุทุงุก ุงูููู
", value=str(daily["errors"]), inline=True)
|
| 90 |
-
embed.add_field(
|
| 91 |
-
name="๐ฆ ุงูููู",
|
| 92 |
-
value=(
|
| 93 |
-
f"ุฏุฎูู: {totals['total_joins']} | "
|
| 94 |
-
f"ุฎุฑูุฌ: {totals['total_leaves']} | "
|
| 95 |
-
f"ุฃุฎุทุงุก: {totals['total_errors']}"
|
| 96 |
-
),
|
| 97 |
-
inline=False,
|
| 98 |
-
)
|
| 99 |
-
embed.set_footer(text=f"ุจุฏุก ุงูููู
: {daily['day_start'][:10]}")
|
| 100 |
-
await interaction.response.send_message(embed=embed, ephemeral=True)
|
| 101 |
-
|
| 102 |
-
# โโ /ุชุฌุฑุจุฉ_ุชุฑุญูุจ โ Test welcome for a member โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 103 |
-
@app_commands.command(name="ุชุฌุฑุจุฉ_ุชุฑุญูุจ", description="ุงุฎุชุจุงุฑ ุฑุณุงูุฉ ุงูุชุฑุญูุจ ูุนุถู ู
ุนูู")
|
| 104 |
-
@app_commands.describe(ุนุถู="ุงูุนุถู ุงูุฐู ุชุฑูุฏ ุชุฌุฑุจุฉ ุงูุชุฑุญูุจ ุจู")
|
| 105 |
-
@app_commands.guilds(discord.Object(id=ALLOWED_GUILD_ID))
|
| 106 |
-
@is_admin()
|
| 107 |
-
async def test_welcome(self, interaction: discord.Interaction, ุนุถู: discord.Member):
|
| 108 |
-
await interaction.response.defer(ephemeral=True)
|
| 109 |
-
try:
|
| 110 |
-
welcome_cog = self.bot.cogs.get("WelcomeCog")
|
| 111 |
-
if not welcome_cog:
|
| 112 |
-
await interaction.followup.send("โ ููุฌ ุงูุชุฑุญูุจ ุบูุฑ ู
ุญู
ูู.", ephemeral=True)
|
| 113 |
-
return
|
| 114 |
-
await welcome_cog.send_welcome(ุนุถู, test_mode=True)
|
| 115 |
-
await interaction.followup.send(
|
| 116 |
-
f"โ
ุชู
ุฅุฑุณุงู ุฑุณุงูุฉ ุชุฑุญูุจ ุชุฌุฑูุจูุฉ ูู {ุนุถู.mention} ูู <#{WELCOME_CHANNEL_ID}>.",
|
| 117 |
-
ephemeral=True,
|
| 118 |
-
)
|
| 119 |
-
except Exception as e:
|
| 120 |
-
logger.error(f"test_welcome error: {e}")
|
| 121 |
-
await interaction.followup.send(f"โ ุญุฏุซ ุฎุทุฃ: {e}", ephemeral=True)
|
| 122 |
-
|
| 123 |
-
# โโ /ุชูุนูู_ุชุฑุญูุจ โ Owner only โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 124 |
-
@app_commands.command(name="ุชูุนูู_ุชุฑุญูุจ", description="[ุงูู
ุงูู] ุชูุนูู ุฃู ุชุนุทูู ูุธุงู
ุงูุชุฑุญูุจ")
|
| 125 |
-
@app_commands.describe(ุญุงูุฉ="ูุนูู ุฃู ุนุทูู ุงูุชุฑุญูุจ")
|
| 126 |
-
@app_commands.choices(ุญุงูุฉ=[
|
| 127 |
-
app_commands.Choice(name="ุชูุนูู", value="on"),
|
| 128 |
-
app_commands.Choice(name="ุชุนุทูู", value="off"),
|
| 129 |
-
])
|
| 130 |
-
@app_commands.guilds(discord.Object(id=ALLOWED_GUILD_ID))
|
| 131 |
-
@is_owner()
|
| 132 |
-
async def toggle_welcome(self, interaction: discord.Interaction, ุญุงูุฉ: str):
|
| 133 |
-
self._welcome_enabled = (ุญุงูุฉ == "on")
|
| 134 |
-
# Propagate to welcome cog (monkey-patch the listener)
|
| 135 |
-
welcome_cog = self.bot.cogs.get("WelcomeCog")
|
| 136 |
-
status = "ู
ูุนูู โ
" if self._welcome_enabled else "ู
ุนุทูู โ"
|
| 137 |
-
|
| 138 |
-
embed = discord.Embed(
|
| 139 |
-
title="โ๏ธ ุชุญุฏูุซ ุฅุนุฏุงุฏุงุช ุงูุชุฑุญูุจ",
|
| 140 |
-
description=f"ูุธุงู
ุงูุชุฑุญูุจ ุงูุขู: **{status}**",
|
| 141 |
-
color=0x57F287 if self._welcome_enabled else 0xED4245,
|
| 142 |
-
)
|
| 143 |
-
await interaction.response.send_message(embed=embed)
|
| 144 |
-
|
| 145 |
-
# โโ /ุฅุญุตุงุฆูุงุช โ Detailed stats (admin) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 146 |
-
@app_commands.command(name="ุฅุญุตุงุฆูุงุช", description="ุนุฑุถ ุฅุญุตุงุฆูุงุช ู
ูุตููุฉ ููุฎุงุฏู
")
|
| 147 |
-
@app_commands.guilds(discord.Object(id=ALLOWED_GUILD_ID))
|
| 148 |
-
@is_admin()
|
| 149 |
-
async def stats_cmd(self, interaction: discord.Interaction):
|
| 150 |
-
history = tracker.get_history(7)
|
| 151 |
-
totals = tracker.get_totals()
|
| 152 |
-
daily = tracker.get_daily()
|
| 153 |
-
|
| 154 |
-
embed = discord.Embed(
|
| 155 |
-
title="๐ ุฅุญุตุงุฆูุงุช ุงูุฎุงุฏู
(ุขุฎุฑ 7 ุฃูุงู
)",
|
| 156 |
-
color=0x7B2FBE,
|
| 157 |
-
timestamp=datetime.now(timezone.utc),
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
if history:
|
| 161 |
-
lines = []
|
| 162 |
-
for h in reversed(history):
|
| 163 |
-
date = h["date"][:10]
|
| 164 |
-
g = h["growth"]
|
| 165 |
-
arrow = "๐" if g >= 0 else "๐"
|
| 166 |
-
lines.append(f"`{date}` {arrow} ุฏุฎูู: **{h['joins']}** ุฎุฑูุฌ: **{h['leaves']}** ูู
ู: **{g:+d}**")
|
| 167 |
-
embed.add_field(name="๐
ุงูุณุฌู ุงูููู
ู", value="\n".join(lines), inline=False)
|
| 168 |
-
else:
|
| 169 |
-
embed.add_field(name="๐
ุงูุณุฌู ุงูููู
ู", value="ูุง ุชูุฌุฏ ุจูุงูุงุช ุจุนุฏ.", inline=False)
|
| 170 |
-
|
| 171 |
-
embed.add_field(name="๐ฅ ุฏุฎูู ุงูููู
", value=str(daily["joins"]), inline=True)
|
| 172 |
-
embed.add_field(name="๐ค ุฎุฑูุฌ ุงูููู
", value=str(daily["leaves"]), inline=True)
|
| 173 |
-
embed.add_field(name="๐ฆ ุฅุฌู
ุงูู ุงูุฏุฎูู ุงูููู", value=str(totals["total_joins"]), inline=True)
|
| 174 |
-
|
| 175 |
-
guild = interaction.guild
|
| 176 |
-
if guild:
|
| 177 |
-
embed.add_field(name="๐ฅ ุงูุฃุนุถุงุก ุงูุญุงูููู", value=str(guild.member_count), inline=True)
|
| 178 |
-
|
| 179 |
-
await interaction.response.send_message(embed=embed, ephemeral=True)
|
| 180 |
-
|
| 181 |
-
# โโ /ู
ุณุงุนุฏุฉ_ุงุฏู
ู โ Help panel โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 182 |
-
@app_commands.command(name="ู
ุณุงุนุฏุฉ_ุงุฏู
ู", description="ุนุฑุถ ูุงุฆู
ุฉ ุงูุฃูุงู
ุฑ ุงูู
ุชุงุญุฉ ููุฅุฏุงุฑุฉ")
|
| 183 |
-
@app_commands.guilds(discord.Object(id=ALLOWED_GUILD_ID))
|
| 184 |
-
@is_admin()
|
| 185 |
-
async def admin_help(self, interaction: discord.Interaction):
|
| 186 |
-
embed = discord.Embed(
|
| 187 |
-
title="๐ ููุญุฉ ุชุญูู
ุงูุฅุฏุงุฑุฉ โ ุงูุฃูุงู
ุฑ ุงูู
ุชุงุญุฉ",
|
| 188 |
-
color=0x7B2FBE,
|
| 189 |
-
)
|
| 190 |
-
embed.add_field(
|
| 191 |
-
name="๐ง ุฃูุงู
ุฑ ุงูุฅุฏุงุฑุฉ",
|
| 192 |
-
value=(
|
| 193 |
-
"`/ุญุงูุฉ` โ ุญุงูุฉ ุงูุจูุช ูุงูุฅุญุตุงุฆูุงุช ุงูููู
ูุฉ\n"
|
| 194 |
-
"`/ุชุฌุฑุจุฉ_ุชุฑุญูุจ @ุนุถู` โ ุงุฎุชุจุงุฑ ุฑุณุงูุฉ ุชุฑุญูุจ ูุนุถู ู
ุนูู\n"
|
| 195 |
-
"`/ุฅุญุตุงุฆูุงุช` โ ุฅุญุตุงุฆูุงุช ู
ูุตููุฉ (7 ุฃูุงู
)\n"
|
| 196 |
-
"`/ู
ุณุงุนุฏุฉ_ุงุฏู
ู` โ ูุฐู ุงููุงุฆู
ุฉ"
|
| 197 |
-
),
|
| 198 |
-
inline=False,
|
| 199 |
-
)
|
| 200 |
-
embed.add_field(
|
| 201 |
-
name="๐ ุฃูุงู
ุฑ ุงูู
ุงูู ููุท",
|
| 202 |
-
value="`/ุชูุนูู_ุชุฑุญูุจ` โ ุชูุนูู ุฃู ุชุนุทูู ูุธุงู
ุงูุชุฑุญูุจ",
|
| 203 |
-
inline=False,
|
| 204 |
-
)
|
| 205 |
-
embed.set_footer(text=f"ุฌู
ูุน ุงูุฃูุงู
ุฑ ุชุนู
ู ููุท ูู ูุฐู ุงูููุงุฉ")
|
| 206 |
-
await interaction.response.send_message(embed=embed, ephemeral=True)
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
async def setup(bot: commands.Bot):
|
| 210 |
-
await bot.add_cog(AdminCog(bot))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cogs/logs.py
DELETED
|
@@ -1,157 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
cogs/logs.py
|
| 3 |
-
Posts to the logs channel:
|
| 4 |
-
- Instant log on every join / leave / error
|
| 5 |
-
- Daily summary every 24 h (growth stats, comparison)
|
| 6 |
-
"""
|
| 7 |
-
|
| 8 |
-
import discord
|
| 9 |
-
from discord.ext import commands, tasks
|
| 10 |
-
import logging
|
| 11 |
-
from datetime import datetime, timezone
|
| 12 |
-
|
| 13 |
-
from config import ALLOWED_GUILD_ID, LOGS_CHANNEL_ID
|
| 14 |
-
from stats import tracker
|
| 15 |
-
|
| 16 |
-
logger = logging.getLogger("WelcomeBot.Logs")
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
class LogsCog(commands.Cog):
|
| 20 |
-
def __init__(self, bot: commands.Bot):
|
| 21 |
-
self.bot = bot
|
| 22 |
-
self.daily_report.start()
|
| 23 |
-
|
| 24 |
-
def cog_unload(self):
|
| 25 |
-
self.daily_report.cancel()
|
| 26 |
-
|
| 27 |
-
def _guild(self) -> discord.Guild | None:
|
| 28 |
-
return self.bot.get_guild(ALLOWED_GUILD_ID)
|
| 29 |
-
|
| 30 |
-
async def _log_channel(self) -> discord.TextChannel | None:
|
| 31 |
-
g = self._guild()
|
| 32 |
-
if g:
|
| 33 |
-
return g.get_channel(LOGS_CHANNEL_ID)
|
| 34 |
-
return None
|
| 35 |
-
|
| 36 |
-
# โโ Instant join log โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 37 |
-
@commands.Cog.listener()
|
| 38 |
-
async def on_member_join(self, member: discord.Member):
|
| 39 |
-
if member.guild.id != ALLOWED_GUILD_ID:
|
| 40 |
-
return
|
| 41 |
-
ch = await self._log_channel()
|
| 42 |
-
if not ch:
|
| 43 |
-
return
|
| 44 |
-
embed = discord.Embed(
|
| 45 |
-
title="๐ฅ ุนุถู ุฌุฏูุฏ",
|
| 46 |
-
description=f"{member.mention} ุงูุถู
ุฅูู ุงูุฎุงุฏู
",
|
| 47 |
-
color=0x57F287,
|
| 48 |
-
timestamp=datetime.now(timezone.utc),
|
| 49 |
-
)
|
| 50 |
-
embed.set_thumbnail(url=member.display_avatar.url)
|
| 51 |
-
embed.add_field(name="ุงูู
ุนุฑูู", value=str(member.id), inline=True)
|
| 52 |
-
embed.add_field(name="ุงูุงุณู
", value=member.name, inline=True)
|
| 53 |
-
embed.add_field(
|
| 54 |
-
name="ุฅุฌู
ุงูู ุงูุฃุนุถุงุก",
|
| 55 |
-
value=str(member.guild.member_count),
|
| 56 |
-
inline=True,
|
| 57 |
-
)
|
| 58 |
-
await ch.send(embed=embed)
|
| 59 |
-
|
| 60 |
-
# โโ Instant leave log โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 61 |
-
@commands.Cog.listener()
|
| 62 |
-
async def on_member_remove(self, member: discord.Member):
|
| 63 |
-
if member.guild.id != ALLOWED_GUILD_ID:
|
| 64 |
-
return
|
| 65 |
-
ch = await self._log_channel()
|
| 66 |
-
if not ch:
|
| 67 |
-
return
|
| 68 |
-
embed = discord.Embed(
|
| 69 |
-
title="๐ค ุนุถู ุบุงุฏุฑ",
|
| 70 |
-
description=f"**{member.name}** ุบุงุฏุฑ ุงูุฎุงุฏู
",
|
| 71 |
-
color=0xED4245,
|
| 72 |
-
timestamp=datetime.now(timezone.utc),
|
| 73 |
-
)
|
| 74 |
-
embed.set_thumbnail(url=member.display_avatar.url)
|
| 75 |
-
embed.add_field(name="ุงูู
ุนุฑูู", value=str(member.id), inline=True)
|
| 76 |
-
guild = self._guild()
|
| 77 |
-
if guild:
|
| 78 |
-
embed.add_field(
|
| 79 |
-
name="ุฅุฌู
ุงูู ุงูุฃุนุถุงุก",
|
| 80 |
-
value=str(guild.member_count),
|
| 81 |
-
inline=True,
|
| 82 |
-
)
|
| 83 |
-
await ch.send(embed=embed)
|
| 84 |
-
|
| 85 |
-
# โโ Error log helper โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 86 |
-
async def log_error(self, description: str):
|
| 87 |
-
ch = await self._log_channel()
|
| 88 |
-
if not ch:
|
| 89 |
-
return
|
| 90 |
-
embed = discord.Embed(
|
| 91 |
-
title="โ ๏ธ ุฎุทุฃ",
|
| 92 |
-
description=description,
|
| 93 |
-
color=0xFEE75C,
|
| 94 |
-
timestamp=datetime.now(timezone.utc),
|
| 95 |
-
)
|
| 96 |
-
await ch.send(embed=embed)
|
| 97 |
-
|
| 98 |
-
# โโ Daily summary task (every 24 h) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 99 |
-
@tasks.loop(hours=24)
|
| 100 |
-
async def daily_report(self):
|
| 101 |
-
ch = await self._log_channel()
|
| 102 |
-
if not ch:
|
| 103 |
-
return
|
| 104 |
-
|
| 105 |
-
summary = tracker.reset_daily()
|
| 106 |
-
joins = summary["joins"]
|
| 107 |
-
leaves = summary["leaves"]
|
| 108 |
-
errors = summary["errors"]
|
| 109 |
-
growth = summary["growth"]
|
| 110 |
-
|
| 111 |
-
totals = tracker.get_totals()
|
| 112 |
-
|
| 113 |
-
# Growth percentage (avoid div/0)
|
| 114 |
-
total_before = totals["total_joins"] - totals["total_leaves"] - growth
|
| 115 |
-
if total_before > 0:
|
| 116 |
-
pct = (growth / total_before) * 100
|
| 117 |
-
pct_str = f"{pct:+.1f}%"
|
| 118 |
-
else:
|
| 119 |
-
pct_str = "โ"
|
| 120 |
-
|
| 121 |
-
color = 0x57F287 if growth >= 0 else 0xED4245
|
| 122 |
-
arrow = "๐" if growth >= 0 else "๐"
|
| 123 |
-
|
| 124 |
-
embed = discord.Embed(
|
| 125 |
-
title="๐ ุชูุฑูุฑ ููู
ู โ ุฅุญุตุงุฆูุงุช ุงูุฎุงุฏู
",
|
| 126 |
-
color=color,
|
| 127 |
-
timestamp=datetime.now(timezone.utc),
|
| 128 |
-
)
|
| 129 |
-
embed.add_field(name="๐ฅ ุฏุฎูู ุงูููู
", value=str(joins), inline=True)
|
| 130 |
-
embed.add_field(name="๐ค ุฎุฑูุฌ ุงูููู
", value=str(leaves), inline=True)
|
| 131 |
-
embed.add_field(name="โ ๏ธ ุฃุฎุทุงุก ุงูููู
", value=str(errors), inline=True)
|
| 132 |
-
embed.add_field(
|
| 133 |
-
name=f"{arrow} ูู
ู ุงูููู
",
|
| 134 |
-
value=f"**{growth:+d}** ุนุถู ({pct_str})",
|
| 135 |
-
inline=False,
|
| 136 |
-
)
|
| 137 |
-
embed.add_field(
|
| 138 |
-
name="๐ฆ ุงูุฅุฌู
ุงูู ุงูููู",
|
| 139 |
-
value=(
|
| 140 |
-
f"ุฏุฎูู: {totals['total_joins']} | "
|
| 141 |
-
f"ุฎุฑูุฌ: {totals['total_leaves']} | "
|
| 142 |
-
f"ุฃุฎุทุงุก: {totals['total_errors']}"
|
| 143 |
-
),
|
| 144 |
-
inline=False,
|
| 145 |
-
)
|
| 146 |
-
embed.set_footer(text="ูุชุฌุฏุฏ ูุฐุง ุงูุชูุฑูุฑ ูู 24 ุณุงุนุฉ")
|
| 147 |
-
|
| 148 |
-
await ch.send(embed=embed)
|
| 149 |
-
logger.info("Daily report posted.")
|
| 150 |
-
|
| 151 |
-
@daily_report.before_loop
|
| 152 |
-
async def before_daily_report(self):
|
| 153 |
-
await self.bot.wait_until_ready()
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
async def setup(bot: commands.Bot):
|
| 157 |
-
await bot.add_cog(LogsCog(bot))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cogs/welcome.py
DELETED
|
@@ -1,126 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
cogs/welcome.py
|
| 3 |
-
Handles the on_member_join event:
|
| 4 |
-
- Sends a professional embed to the welcome channel
|
| 5 |
-
- Reacts with ๐
|
| 6 |
-
- Sends the personalized welcome card image (avatar composited on crown PNG)
|
| 7 |
-
"""
|
| 8 |
-
|
| 9 |
-
import discord
|
| 10 |
-
from discord.ext import commands
|
| 11 |
-
from discord import app_commands
|
| 12 |
-
import random
|
| 13 |
-
import logging
|
| 14 |
-
from datetime import datetime, timezone
|
| 15 |
-
|
| 16 |
-
from config import ALLOWED_GUILD_ID, WELCOME_CHANNEL_ID
|
| 17 |
-
from image_processor import generate_welcome_card
|
| 18 |
-
from stats import tracker
|
| 19 |
-
|
| 20 |
-
logger = logging.getLogger("WelcomeBot.Welcome")
|
| 21 |
-
|
| 22 |
-
# โโ Welcome messages pool โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 23 |
-
WELCOME_MESSAGES = [
|
| 24 |
-
"ุฃููุงู ูุณููุงู ุจู ูู ู
ุฌุชู
ุนูุง! ุณุนุฏุงุก ุจุงูุถู
ุงู
ู ุฅูููุง ๐",
|
| 25 |
-
"ู
ุฑุญุจุงู ุจู ูู ุฎุงุฏู
ูุง! ูุชู
ูู ุฃู ุชุฌุฏ ููุชุงู ู
ู
ุชุนุงู ู
ุนูุง โจ",
|
| 26 |
-
"ูุณุนุฏูุง ูุฌูุฏู ุจูููุง! ุฃููุงู ุจู ูู ุนุงุฆูุชูุง ุงูุตุบูุฑุฉ ๐",
|
| 27 |
-
"ูุตู ุนุถู ุฌุฏูุฏ! ู
ุฑุญุจุงู ุจูุ ูุชู
ูู ูู ุฅูุงู
ุฉ ุทูุจุฉ ๐",
|
| 28 |
-
"ุฃููุงู ุจู ุจูููุง! ุงูุฎุงุฏู
ุฃุตุจุญ ุฃุฌู
ู ุจูุฌูุฏู ๐ฎ",
|
| 29 |
-
"ู
ุฑุญุจุงู ุจู ูู ู
ุฌุชู
ุนูุง ุงูู
ู
ูุฒ! ูุญู ุณุนุฏุงุก ุจูุฏูู
ู ๐ซ",
|
| 30 |
-
"ูุตูุช ูู ุงูููุช ุงูู
ูุงุณุจ! ู
ุฑุญุจุงู ุจู ูู ุฎุงุฏู
ูุง ๐",
|
| 31 |
-
"ุฃููุงู ูุณููุงู! ูุชู
ูู ุฃู ุชุดุนุฑ ุจุงูุฑุงุญุฉ ุจูููุง ุฏุงุฆู
ุงู ๐",
|
| 32 |
-
]
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
class WelcomeCog(commands.Cog):
|
| 36 |
-
def __init__(self, bot: commands.Bot):
|
| 37 |
-
self.bot = bot
|
| 38 |
-
|
| 39 |
-
# โโ Guard: only run in the allowed guild โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 40 |
-
def _is_allowed_guild(self, guild_id: int) -> bool:
|
| 41 |
-
return guild_id == ALLOWED_GUILD_ID
|
| 42 |
-
|
| 43 |
-
# โโ Core welcome sender โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 44 |
-
async def send_welcome(self, member: discord.Member, test_mode: bool = False):
|
| 45 |
-
"""Send welcome embed + card to the welcome channel."""
|
| 46 |
-
guild = member.guild
|
| 47 |
-
|
| 48 |
-
if not self._is_allowed_guild(guild.id):
|
| 49 |
-
logger.warning(f"Ignored member join from guild {guild.id}")
|
| 50 |
-
return
|
| 51 |
-
|
| 52 |
-
channel = guild.get_channel(WELCOME_CHANNEL_ID)
|
| 53 |
-
if not channel:
|
| 54 |
-
logger.error(f"Welcome channel {WELCOME_CHANNEL_ID} not found.")
|
| 55 |
-
tracker.record_error()
|
| 56 |
-
return
|
| 57 |
-
|
| 58 |
-
welcome_msg = random.choice(WELCOME_MESSAGES)
|
| 59 |
-
member_count = guild.member_count
|
| 60 |
-
join_time = member.joined_at or datetime.now(timezone.utc)
|
| 61 |
-
|
| 62 |
-
# โโ Embed โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 63 |
-
embed = discord.Embed(
|
| 64 |
-
title=f"โจ ุนุถู ุฌุฏูุฏ ุงูุถู
ุฅูููุง!",
|
| 65 |
-
description=f"**{welcome_msg}**",
|
| 66 |
-
color=0x7B2FBE,
|
| 67 |
-
timestamp=join_time,
|
| 68 |
-
)
|
| 69 |
-
embed.set_thumbnail(url=member.display_avatar.url)
|
| 70 |
-
embed.add_field(
|
| 71 |
-
name="๐ค ุงูุนุถู",
|
| 72 |
-
value=f"{member.mention}\n`{member.name}`",
|
| 73 |
-
inline=True,
|
| 74 |
-
)
|
| 75 |
-
embed.add_field(
|
| 76 |
-
name="๐
ุชุงุฑูุฎ ุงูุงูุถู
ุงู
",
|
| 77 |
-
value=f"<t:{int(join_time.timestamp())}:F>",
|
| 78 |
-
inline=True,
|
| 79 |
-
)
|
| 80 |
-
embed.add_field(
|
| 81 |
-
name="๐ฅ ุนุฏุฏ ุงูุฃุนุถุงุก",
|
| 82 |
-
value=f"ุฃุตุจุญ ุนุฏุฏ ุฃุนุถุงุฆูุง **{member_count}** ุนุถูุงู",
|
| 83 |
-
inline=False,
|
| 84 |
-
)
|
| 85 |
-
embed.set_footer(
|
| 86 |
-
text=f"{'[ูุถุน ุงูุชุฌุฑุจุฉ] ' if test_mode else ''}ุฎุงุฏู
{guild.name}",
|
| 87 |
-
icon_url=guild.icon.url if guild.icon else None,
|
| 88 |
-
)
|
| 89 |
-
|
| 90 |
-
# โโ Send embed โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 91 |
-
try:
|
| 92 |
-
sent = await channel.send(embed=embed)
|
| 93 |
-
await sent.add_reaction("๐")
|
| 94 |
-
except Exception as e:
|
| 95 |
-
logger.error(f"Failed to send welcome embed: {e}")
|
| 96 |
-
tracker.record_error()
|
| 97 |
-
return
|
| 98 |
-
|
| 99 |
-
# โโ Generate and send welcome card โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 100 |
-
try:
|
| 101 |
-
avatar_url = member.display_avatar.with_format("png").with_size(512).url
|
| 102 |
-
card_bytes = await generate_welcome_card(avatar_url, member.name)
|
| 103 |
-
file = discord.File(fp=card_bytes, filename="welcome.png")
|
| 104 |
-
await channel.send(file=file)
|
| 105 |
-
except Exception as e:
|
| 106 |
-
logger.error(f"Failed to send welcome card image: {e}")
|
| 107 |
-
tracker.record_error()
|
| 108 |
-
|
| 109 |
-
if not test_mode:
|
| 110 |
-
tracker.record_join()
|
| 111 |
-
|
| 112 |
-
# โโ Event โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 113 |
-
@commands.Cog.listener()
|
| 114 |
-
async def on_member_join(self, member: discord.Member):
|
| 115 |
-
logger.info(f"Member joined: {member} in guild {member.guild.id}")
|
| 116 |
-
await self.send_welcome(member)
|
| 117 |
-
|
| 118 |
-
@commands.Cog.listener()
|
| 119 |
-
async def on_member_remove(self, member: discord.Member):
|
| 120 |
-
if self._is_allowed_guild(member.guild.id):
|
| 121 |
-
tracker.record_leave()
|
| 122 |
-
logger.info(f"Member left: {member}")
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
async def setup(bot: commands.Bot):
|
| 126 |
-
await bot.add_cog(WelcomeCog(bot))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|