Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
update for huggingscience server
Browse files
app.py
CHANGED
|
@@ -31,12 +31,29 @@ bot = commands.Bot(command_prefix='!', intents=intents, max_messages=1000000)
|
|
| 31 |
logger = logging.getLogger(__name__)
|
| 32 |
logging.basicConfig(level=logging.DEBUG)
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
#rate_limiter = RateLimiter(max_calls=10, period=60) # needs testing
|
| 35 |
message_cache = {}
|
| 36 |
|
| 37 |
AUTO_BAN_ALERT_THRESHOLD = 7
|
| 38 |
-
AUTO_BAN_EXEMPT_ROLE_IDS =
|
| 39 |
-
# moderator = 1078351789843292311
|
| 40 |
|
| 41 |
def is_exempt(member: discord.Member) -> bool:
|
| 42 |
return any(getattr(r, "id", None) in AUTO_BAN_EXEMPT_ROLE_IDS for r in getattr(member, "roles", []))
|
|
@@ -52,8 +69,8 @@ async def on_message(message):
|
|
| 52 |
global number_of_messages
|
| 53 |
if message.author != bot.user:
|
| 54 |
message_cache[message.id] = message
|
| 55 |
-
|
| 56 |
-
|
| 57 |
"""Backup"""
|
| 58 |
|
| 59 |
number_of_messages = number_of_messages + 1
|
|
@@ -69,20 +86,22 @@ async def on_message(message):
|
|
| 69 |
if message.embeds:
|
| 70 |
for embed in message.embeds:
|
| 71 |
backup_message += f"\nEmbed Title: {embed.title}\nEmbed Description: {embed.description}"
|
| 72 |
-
|
|
|
|
| 73 |
|
| 74 |
"""Antispam"""
|
| 75 |
#Detecting certain unwanted strings
|
| 76 |
try:
|
| 77 |
-
forbidden_patterns = [r"@everyone",
|
| 78 |
-
r"@here",
|
| 79 |
r"(https?:\/\/|http?:\/\/)?(www.)?(discord.(gg|io|me|li)|discordapp.com\/invite|discord.com\/invite)\/[^\s\/]+?(?=\b)"]
|
| 80 |
if any(re.search(pattern, message.content, re.IGNORECASE) for pattern in forbidden_patterns):
|
| 81 |
-
ignored_role_ids =
|
| 82 |
if any(role.id in ignored_role_ids for role in message.author.roles):
|
| 83 |
-
if message.author !=
|
| 84 |
return
|
| 85 |
-
|
|
|
|
| 86 |
except Exception as e:
|
| 87 |
print(f"Antispam->Detecting certain unwanted strings Error: {e}")
|
| 88 |
|
|
@@ -127,7 +146,7 @@ async def on_message(message):
|
|
| 127 |
# warning for 4+
|
| 128 |
channel = message.channel
|
| 129 |
if spam_count == false_positive_threshold:
|
| 130 |
-
if channel.id !=
|
| 131 |
await channel.send(f"{message.author.mention}, you may be posting too quickly! Please slow down a bit 🤗")
|
| 132 |
|
| 133 |
var1 = message.created_at
|
|
@@ -135,11 +154,7 @@ async def on_message(message):
|
|
| 135 |
print(f"seconds since last message by {message.author}: {(var1 - var2).total_seconds()}")
|
| 136 |
print(f"spam_count: {spam_count}")
|
| 137 |
|
| 138 |
-
|
| 139 |
-
if test_server == 'True':
|
| 140 |
-
alert = "<@&1106995261487710411>" # test @alerts role
|
| 141 |
-
if test_server == 'False':
|
| 142 |
-
alert = "<@&1108342563628404747>" # normal @alerts role
|
| 143 |
|
| 144 |
await bot.log_channel.send(
|
| 145 |
f"[EXPERIMENTAL ALERT] {message.author} may be posting too quickly! \n"
|
|
@@ -162,13 +177,7 @@ async def on_message(message):
|
|
| 162 |
print("Autoban: could not resolve Member, skipping.")
|
| 163 |
else:
|
| 164 |
# Prepare alert ping safely
|
| 165 |
-
|
| 166 |
-
if test_server == 'True':
|
| 167 |
-
alert = "<@&1106995261487710411>" # test alerts
|
| 168 |
-
elif test_server == 'False':
|
| 169 |
-
alert = "<@&1108342563628404747>" # prod alerts
|
| 170 |
-
else:
|
| 171 |
-
alert = "" # no ping fallback
|
| 172 |
|
| 173 |
# Skip bots and exempt roles
|
| 174 |
if member.bot or is_exempt(member):
|
|
@@ -194,7 +203,7 @@ async def on_message(message):
|
|
| 194 |
try:
|
| 195 |
await member.send(
|
| 196 |
f"You have been automatically banned from **{message.guild.name}** for repeated spam. "
|
| 197 |
-
f"If this was an error, please contact @
|
| 198 |
)
|
| 199 |
except Exception as dm_err:
|
| 200 |
print(f"Could not DM user before ban: {dm_err}")
|
|
@@ -372,7 +381,7 @@ async def on_member_ban(guild, banned_user):
|
|
| 372 |
else:
|
| 373 |
print(f'{entry2.user} banned {entry2.target} (no reason specified)')
|
| 374 |
|
| 375 |
-
content = "<@&
|
| 376 |
embed = Embed(color=Color.red())
|
| 377 |
embed.set_author(name=f"{entry2.target} ID: {entry2.target.id}", icon_url=entry2.target.avatar.url if entry2.target.avatar else bot.user.avatar.url)
|
| 378 |
embed.title = "User Banned"
|
|
@@ -385,11 +394,10 @@ async def on_member_ban(guild, banned_user):
|
|
| 385 |
embed.add_field(name="Reason", value=ban_reason, inline=False)
|
| 386 |
embed.set_footer(text=f"{convert_to_timezone(datetime.utcnow(), zurich_tz)}")
|
| 387 |
|
| 388 |
-
|
| 389 |
-
await bot.log_channel.send(content=content, embed=embed)
|
| 390 |
|
| 391 |
try:
|
| 392 |
-
dm_message = await banned_user.send(f"You've been banned from
|
| 393 |
except Exception as e:
|
| 394 |
print(f"Could not send DM to banned user: {e}")
|
| 395 |
|
|
@@ -407,7 +415,7 @@ async def on_member_unban(guild, unbanned_user):
|
|
| 407 |
moderator = entry.user
|
| 408 |
|
| 409 |
created_and_age = f"{unbanned_user.created_at}"
|
| 410 |
-
content = "<@&
|
| 411 |
embed = Embed(color=Color.red())
|
| 412 |
embed.set_author(name=f"{unbanned_user} ID: {unbanned_user.id}", icon_url=unbanned_user.avatar.url if unbanned_user.avatar else bot.user.avatar.url)
|
| 413 |
embed.title = "User Unbanned"
|
|
@@ -416,10 +424,8 @@ async def on_member_unban(guild, unbanned_user):
|
|
| 416 |
embed.add_field(name="Moderator", value=moderator.mention, inline=True)
|
| 417 |
embed.add_field(name="Nickname", value=moderator.nick, inline=True)
|
| 418 |
embed.set_footer(text=f"{convert_to_timezone(datetime.utcnow(), zurich_tz)}")
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
#dm_message = await user.send(content=content, embed=embed)
|
| 422 |
-
await bot.log_channel.send(content=content, embed=embed)
|
| 423 |
|
| 424 |
except Exception as e:
|
| 425 |
print(f"on_member_unban Error: {e}")
|
|
@@ -431,7 +437,7 @@ async def on_member_unban(guild, unbanned_user):
|
|
| 431 |
async def on_member_join(member):
|
| 432 |
try:
|
| 433 |
await asyncio.sleep(5)
|
| 434 |
-
guild = bot.get_guild(
|
| 435 |
|
| 436 |
embed = Embed(color=Color.blue())
|
| 437 |
avatar_url = member.avatar.url if member.avatar else bot.user.avatar.url
|
|
@@ -524,25 +530,6 @@ async def on_guild_role_delete(role):
|
|
| 524 |
print(f"on_guild_role_delete Error: {e}")
|
| 525 |
|
| 526 |
|
| 527 |
-
@bot.event
|
| 528 |
-
async def on_guild_role_update(before, after):
|
| 529 |
-
try:
|
| 530 |
-
# editing roles, could expand this
|
| 531 |
-
if before.name != after.name:
|
| 532 |
-
embed = Embed(description=f'Role {before.mention} was renamed to {after.name}', color=Color.orange())
|
| 533 |
-
await bot.log_channel.send(embed=embed)
|
| 534 |
-
|
| 535 |
-
if before.permissions.administrator != after.permissions.administrator:
|
| 536 |
-
# changes involving the administrator permission / sensitive permissions (can help to prevent mistakes)
|
| 537 |
-
content = "<@&1108342563628404747>" # @alerts role
|
| 538 |
-
embed = Embed(description=f'Role {after.mention} had its administrator permission {"enabled" if after.permissions.administrator else "disabled"}', color=Color.red())
|
| 539 |
-
await bot.log_channel.send(content=content, embed=embed)
|
| 540 |
-
except Exception as e:
|
| 541 |
-
print(f"on_guild_role_update Error: {e}")
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
|
| 547 |
|
| 548 |
@bot.event
|
|
@@ -651,14 +638,16 @@ class PersistentRoleSelectionView(View):
|
|
| 651 |
# Command that sends the role buttons message.
|
| 652 |
@bot.command(name="role_buttons")
|
| 653 |
async def role_buttons(ctx):
|
| 654 |
-
# Only
|
| 655 |
-
if ctx.author.id !=
|
| 656 |
await ctx.send("You are not authorized to use this command.", delete_after=10)
|
| 657 |
return
|
| 658 |
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
|
|
|
|
|
|
| 662 |
|
| 663 |
# Create the persistent view.
|
| 664 |
view = PersistentRoleSelectionView(roles)
|
|
@@ -691,24 +680,27 @@ async def on_ready():
|
|
| 691 |
await asyncio.sleep(5)
|
| 692 |
print('Logged on as', bot.user)
|
| 693 |
await asyncio.sleep(5)
|
| 694 |
-
bot.log_channel = bot.get_channel(
|
| 695 |
await asyncio.sleep(5)
|
| 696 |
print(bot.log_channel)
|
| 697 |
-
guild = bot.get_guild(
|
| 698 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 699 |
if guild:
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
-
|
| 709 |
-
except Exception as e:
|
| 710 |
-
print(f"An error occurred while fetching messages from {channel.name}: {e}")
|
| 711 |
-
await asyncio.sleep(0.1)
|
| 712 |
|
| 713 |
|
| 714 |
|
|
|
|
| 31 |
logger = logging.getLogger(__name__)
|
| 32 |
logging.basicConfig(level=logging.DEBUG)
|
| 33 |
|
| 34 |
+
# ============================================================
|
| 35 |
+
# CONFIGURATION — edit these for your server
|
| 36 |
+
# ============================================================
|
| 37 |
+
GUILD_ID = 1417920887549857874 # your server's ID
|
| 38 |
+
LOG_CHANNEL_ID = 1418169465555910699 # channel where mod events are posted
|
| 39 |
+
ADMIN_USER_ID = 847651116863062047 # ban-appeal contact + owner of !role_buttons
|
| 40 |
+
EXEMPT_ROLE_IDS = { # roles exempt from spam detection / autoban
|
| 41 |
+
1418158261735264327,
|
| 42 |
+
1419966815559225344,
|
| 43 |
+
1418179704065884243,
|
| 44 |
+
1418886227830112297,
|
| 45 |
+
1418510579894845472,
|
| 46 |
+
}
|
| 47 |
+
ALERT_ROLE_ID = 1418510579894845472 # role pinged on spam alerts / bans
|
| 48 |
+
ADMIN_CHANNEL_ID = None # set to a channel ID to suppress spam warnings there
|
| 49 |
+
SELF_ASSIGN_ROLE_IDS = [] # role IDs for !role_buttons (empty disables)
|
| 50 |
+
# ============================================================
|
| 51 |
+
|
| 52 |
#rate_limiter = RateLimiter(max_calls=10, period=60) # needs testing
|
| 53 |
message_cache = {}
|
| 54 |
|
| 55 |
AUTO_BAN_ALERT_THRESHOLD = 7
|
| 56 |
+
AUTO_BAN_EXEMPT_ROLE_IDS = EXEMPT_ROLE_IDS
|
|
|
|
| 57 |
|
| 58 |
def is_exempt(member: discord.Member) -> bool:
|
| 59 |
return any(getattr(r, "id", None) in AUTO_BAN_EXEMPT_ROLE_IDS for r in getattr(member, "roles", []))
|
|
|
|
| 69 |
global number_of_messages
|
| 70 |
if message.author != bot.user:
|
| 71 |
message_cache[message.id] = message
|
| 72 |
+
admin_user = bot.get_user(ADMIN_USER_ID)
|
| 73 |
+
|
| 74 |
"""Backup"""
|
| 75 |
|
| 76 |
number_of_messages = number_of_messages + 1
|
|
|
|
| 86 |
if message.embeds:
|
| 87 |
for embed in message.embeds:
|
| 88 |
backup_message += f"\nEmbed Title: {embed.title}\nEmbed Description: {embed.description}"
|
| 89 |
+
if admin_user is not None:
|
| 90 |
+
dm_message = await admin_user.send(backup_message)
|
| 91 |
|
| 92 |
"""Antispam"""
|
| 93 |
#Detecting certain unwanted strings
|
| 94 |
try:
|
| 95 |
+
forbidden_patterns = [r"@everyone",
|
| 96 |
+
r"@here",
|
| 97 |
r"(https?:\/\/|http?:\/\/)?(www.)?(discord.(gg|io|me|li)|discordapp.com\/invite|discord.com\/invite)\/[^\s\/]+?(?=\b)"]
|
| 98 |
if any(re.search(pattern, message.content, re.IGNORECASE) for pattern in forbidden_patterns):
|
| 99 |
+
ignored_role_ids = list(EXEMPT_ROLE_IDS)
|
| 100 |
if any(role.id in ignored_role_ids for role in message.author.roles):
|
| 101 |
+
if message.author.id != ADMIN_USER_ID:
|
| 102 |
return
|
| 103 |
+
if admin_user is not None:
|
| 104 |
+
dm_unwanted = await admin_user.send(f" {admin_user.mention} [experimental] SUSPICIOUS MESSAGE: {message_link} | {message.author}: {message.content}")
|
| 105 |
except Exception as e:
|
| 106 |
print(f"Antispam->Detecting certain unwanted strings Error: {e}")
|
| 107 |
|
|
|
|
| 146 |
# warning for 4+
|
| 147 |
channel = message.channel
|
| 148 |
if spam_count == false_positive_threshold:
|
| 149 |
+
if ADMIN_CHANNEL_ID is None or channel.id != ADMIN_CHANNEL_ID:
|
| 150 |
await channel.send(f"{message.author.mention}, you may be posting too quickly! Please slow down a bit 🤗")
|
| 151 |
|
| 152 |
var1 = message.created_at
|
|
|
|
| 154 |
print(f"seconds since last message by {message.author}: {(var1 - var2).total_seconds()}")
|
| 155 |
print(f"spam_count: {spam_count}")
|
| 156 |
|
| 157 |
+
alert = f"<@&{ALERT_ROLE_ID}>"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
|
| 159 |
await bot.log_channel.send(
|
| 160 |
f"[EXPERIMENTAL ALERT] {message.author} may be posting too quickly! \n"
|
|
|
|
| 177 |
print("Autoban: could not resolve Member, skipping.")
|
| 178 |
else:
|
| 179 |
# Prepare alert ping safely
|
| 180 |
+
alert = f"<@&{ALERT_ROLE_ID}>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
# Skip bots and exempt roles
|
| 183 |
if member.bot or is_exempt(member):
|
|
|
|
| 203 |
try:
|
| 204 |
await member.send(
|
| 205 |
f"You have been automatically banned from **{message.guild.name}** for repeated spam. "
|
| 206 |
+
f"If this was an error, please contact <@{ADMIN_USER_ID}>."
|
| 207 |
)
|
| 208 |
except Exception as dm_err:
|
| 209 |
print(f"Could not DM user before ban: {dm_err}")
|
|
|
|
| 381 |
else:
|
| 382 |
print(f'{entry2.user} banned {entry2.target} (no reason specified)')
|
| 383 |
|
| 384 |
+
content = f"<@&{ALERT_ROLE_ID}>"
|
| 385 |
embed = Embed(color=Color.red())
|
| 386 |
embed.set_author(name=f"{entry2.target} ID: {entry2.target.id}", icon_url=entry2.target.avatar.url if entry2.target.avatar else bot.user.avatar.url)
|
| 387 |
embed.title = "User Banned"
|
|
|
|
| 394 |
embed.add_field(name="Reason", value=ban_reason, inline=False)
|
| 395 |
embed.set_footer(text=f"{convert_to_timezone(datetime.utcnow(), zurich_tz)}")
|
| 396 |
|
| 397 |
+
await bot.log_channel.send(content=content, embed=embed)
|
|
|
|
| 398 |
|
| 399 |
try:
|
| 400 |
+
dm_message = await banned_user.send(f"You've been banned from {guild.name}. To appeal, reach out to <@{ADMIN_USER_ID}> via DM")
|
| 401 |
except Exception as e:
|
| 402 |
print(f"Could not send DM to banned user: {e}")
|
| 403 |
|
|
|
|
| 415 |
moderator = entry.user
|
| 416 |
|
| 417 |
created_and_age = f"{unbanned_user.created_at}"
|
| 418 |
+
content = f"<@&{ALERT_ROLE_ID}>"
|
| 419 |
embed = Embed(color=Color.red())
|
| 420 |
embed.set_author(name=f"{unbanned_user} ID: {unbanned_user.id}", icon_url=unbanned_user.avatar.url if unbanned_user.avatar else bot.user.avatar.url)
|
| 421 |
embed.title = "User Unbanned"
|
|
|
|
| 424 |
embed.add_field(name="Moderator", value=moderator.mention, inline=True)
|
| 425 |
embed.add_field(name="Nickname", value=moderator.nick, inline=True)
|
| 426 |
embed.set_footer(text=f"{convert_to_timezone(datetime.utcnow(), zurich_tz)}")
|
| 427 |
+
|
| 428 |
+
await bot.log_channel.send(content=content, embed=embed)
|
|
|
|
|
|
|
| 429 |
|
| 430 |
except Exception as e:
|
| 431 |
print(f"on_member_unban Error: {e}")
|
|
|
|
| 437 |
async def on_member_join(member):
|
| 438 |
try:
|
| 439 |
await asyncio.sleep(5)
|
| 440 |
+
guild = bot.get_guild(GUILD_ID)
|
| 441 |
|
| 442 |
embed = Embed(color=Color.blue())
|
| 443 |
avatar_url = member.avatar.url if member.avatar else bot.user.avatar.url
|
|
|
|
| 530 |
print(f"on_guild_role_delete Error: {e}")
|
| 531 |
|
| 532 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 533 |
|
| 534 |
|
| 535 |
@bot.event
|
|
|
|
| 638 |
# Command that sends the role buttons message.
|
| 639 |
@bot.command(name="role_buttons")
|
| 640 |
async def role_buttons(ctx):
|
| 641 |
+
# Only the configured admin user is allowed to invoke this command.
|
| 642 |
+
if ctx.author.id != ADMIN_USER_ID:
|
| 643 |
await ctx.send("You are not authorized to use this command.", delete_after=10)
|
| 644 |
return
|
| 645 |
|
| 646 |
+
if not SELF_ASSIGN_ROLE_IDS:
|
| 647 |
+
await ctx.send("No self-assignable roles configured. Set SELF_ASSIGN_ROLE_IDS in app.py.", delete_after=15)
|
| 648 |
+
return
|
| 649 |
+
|
| 650 |
+
roles = [ctx.guild.get_role(rid) for rid in SELF_ASSIGN_ROLE_IDS if ctx.guild.get_role(rid) is not None]
|
| 651 |
|
| 652 |
# Create the persistent view.
|
| 653 |
view = PersistentRoleSelectionView(roles)
|
|
|
|
| 680 |
await asyncio.sleep(5)
|
| 681 |
print('Logged on as', bot.user)
|
| 682 |
await asyncio.sleep(5)
|
| 683 |
+
bot.log_channel = bot.get_channel(LOG_CHANNEL_ID)
|
| 684 |
await asyncio.sleep(5)
|
| 685 |
print(bot.log_channel)
|
| 686 |
+
guild = bot.get_guild(GUILD_ID)
|
| 687 |
+
|
| 688 |
+
if guild and SELF_ASSIGN_ROLE_IDS:
|
| 689 |
+
roles = [guild.get_role(rid) for rid in SELF_ASSIGN_ROLE_IDS if guild.get_role(rid) is not None]
|
| 690 |
+
if roles:
|
| 691 |
+
persistent_view = PersistentRoleSelectionView(roles)
|
| 692 |
+
bot.add_view(persistent_view) # This makes the view persistent across restarts.
|
| 693 |
+
|
| 694 |
if guild:
|
| 695 |
+
for channel in guild.text_channels: # helps with more accurate logging across restarts
|
| 696 |
+
try:
|
| 697 |
+
message_cache.update({m.id: m async for m in channel.history(limit=10000)})
|
| 698 |
+
print(f"Finished caching messages for channel: {channel.name}")
|
| 699 |
+
except Exception as e:
|
| 700 |
+
print(f"An error occurred while fetching messages from {channel.name}: {e}")
|
| 701 |
+
await asyncio.sleep(0.1)
|
| 702 |
+
else:
|
| 703 |
+
print(f"on_ready: could not find guild with ID {GUILD_ID}. Is the bot in the server?")
|
|
|
|
|
|
|
|
|
|
| 704 |
|
| 705 |
|
| 706 |
|