Created
April 4, 2025 22:26
-
-
Save SpotlightForBugs/efd569b6adbebd8cfe123ec888df1356 to your computer and use it in GitHub Desktop.
Telegram bot that removes non-admin invite link messages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
import asyncio | |
import logging | |
import os | |
import re | |
import random | |
from aiogram import Bot, Dispatcher, F | |
from aiogram.enums import ChatType, ChatMemberStatus | |
from aiogram.exceptions import TelegramAPIError | |
from aiogram.filters import Command | |
from aiogram.types import Message, ChatMember | |
# --- Configuration --- | |
# WARNING: Hardcoding the token is insecure. Use environment variables instead. | |
API_TOKEN = "YOUR_BOT_TOKEN_HERE" # !!! REPLACE WITH YOUR ACTUAL BOT TOKEN !!! | |
# List of celebratory phrases (German/English mix, puns, student/tech theme) | |
CELEBRATORY_PHRASES = [ | |
# Basic & Direct | |
"💥 Boom! Spam-Link? More like Tele-GONE! User wurde *verbannt*! 😎", | |
"🧹 Sweep Sweep! Another spammer *rausgeflogen*! FH Aachen bleibt sauber! ✨", | |
"🛡️ Firewall Activated! Böser Link *neutralisiert*, User ist jetzt `404 Not Found`! 😉", | |
"🚫 Access Denied! Spam-Link geblockt, User *gekickt*! ✅", | |
"🚨 Alarm! Spam detected! User wurde *fachgerecht entsorgt*. Mission accomplished! 👍", | |
"⚡️ Zack! Schneller gebannt als das BAföG alle ist! Spam-Link *eliminiert*! 💸", | |
"🗑️ Ab in die Tonne! Dieser Link war digitaler *Müll*. User recycled! ♻️", | |
"✌️ Peace out, Spammer! Dein Link war *unerwünscht*. Chat bleibt nice! 😎", | |
"🎉 Hooray! Unwanted link poster banned successfully! 👍", | |
"🎯 Target locked & eliminated! Spammer *deaktiviert*. Chat secured! 🛡️", | |
# Student / FH Aachen Themed | |
"🎓 Exmatrikuliert! Dieser Link bekommt keine ECTS hier! Spammer *gekickt*! 🎉", | |
"🤓 Nachsitzen für den Spammer – aber *permanent*! Link gelöscht, User gebannt! 📝", | |
"🧐 Prüfung nicht bestanden! Thema: 'Keine Spam-Links'. User *durchgefallen* & gebannt! ❌", | |
"📚 Lernphase beendet! User hat gelernt: Keine Spam-Links! (Leider zu spät). *Gebannt*! 😅", | |
"🏛️ Campusverweis erteilt! Dieser Link gehört hier nicht hin. User *rausgeworfen*! 🚪", | |
" Mensa-Verbot für den Spammer! Und Chat-Verbot natürlich auch. *Gebannt*! 🍕", | |
"📈 Spam-Kurve auf Null gedrückt! User-Account *terminiert*. Läuft! 😉", | |
"💡 Glühbirne! Idee: Kein Spam! User wurde *ausgeknipst*! Chat bleibt hell! ✨", | |
" Aachen bleibt *spamfrei*! Link-Poster wurde des Campus verwiesen! 🛡️", | |
"⏰ Zu spät! Die Deadline für 'Nicht-Spammen' wurde verpasst. User *gebannt*! ⏳", | |
# Tech / Pun Themed | |
"🤖 Banhammer deployed! User hat einen *fatal error* im Chat verursacht. System stable now! ✅", | |
"😂 Link-Fail! Der war wohl nix. User *abgeschossen*! Keep the chat clean! 🥳", | |
"🍻 Prost! Auf einen sauberen Chat! Spammer wurde *ins digitale Nirvana* geschickt! ✨", | |
"🧐 Spam-Link? Das gibt 'nen *Compile Error* für den User-Account! Access denied! 🚫", | |
"💾 User data? Deleted. Access? Revoked. Spam? *Neutralized*. 😎", | |
"🔌 Stecker gezogen! Der Spam-Link hat keine Power mehr. User *offline* geschaltet! 🚫", | |
"🖱️ Rechtsklick -> Ban! So einfach geht das. Spammer *entfernt*! ✨", | |
"👾 Glitch in the Matrix behoben! Der Spam-Agent wurde *eliminiert*. Reloading chat... ✅", | |
"☁️ Ab in die Cloud... of banned users! Spam-Link *verdampft*! 💨", | |
"🔐 Security Breach verhindert! Spammer *isoliert* und gebannt! System sicher. 🛡️", | |
# More variations | |
"💥 Peng! Link zerschossen, Spammer *verbannt*! Ordnung muss sein! 😉", | |
"🧹 Kehrwoche im Chat! Spam wurde *weggefegt*, User gleich mit! ✨", | |
"🛡️ Schild hoch! Kein Durchkommen für Spam-Links! User *abgewehrt* & gebannt! 🚫", | |
"🚫 Rote Karte für den Spammer! Unfaires Spiel -> Platzverweis! *Gebannt*! 🟥", | |
"🚨 Sirenen heulen! Spam-Angriff abgewehrt! User *festgenommen* (gebannt)! 👍", | |
"⚡️ Blitzschlag! Spam-Link *getroffen*, User *vaporisiert*! 😎", | |
"🗑️ Müllabfuhr war da! Spam-Link *entsorgt*, User mitgenommen! ♻️", | |
"✌️ Tschüssikowski, Spammer! Dein Link war *nicht cool*. Chat bleibt chillig! 😉", | |
"🎉 Konfetti! Wir feiern einen spamfreien Chat! User *verabschiedet* (gebannt)! 🥳", | |
"🎯 Volltreffer! Spam-Link identifiziert, User *ausgeschaltet*! ✅", | |
"🎓 Semesterferien für den Spammer! Aber *für immer*. Gebannt! 🌴", | |
"🤓 Brille aufgesetzt, Spam erkannt! User *analysiert* und gebannt! 🧐", | |
"🧐 Logikfehler im System: User postet Spam. Korrektur: User *bannen*! ✅", | |
"📚 Hausordnung §1: Kein Spam! Verstoß -> *Bann*! User hat's erwischt! 📝", | |
"🏛️ Audimax ist voll? Egal, für Spammer ist hier eh kein Platz! *Gebannt*! 🚫", | |
" Mensa-Tablett abgeräumt, Spam-Link *weggewischt*, User gebannt! ✨", | |
"📈 Performance-Optimierung: Spam entfernt, User *gebannt*. Chat läuft smoother! 😉", | |
"💡 Erleuchtung: Spam ist doof! User wurde *ins Dunkle* (Bann) geschickt! 😅", | |
" Aachener Printen > Spam-Links! User *verkrümelt* (gebannt)! 🍪", | |
"⏰ Wecker gestellt: Zeit für den Bann! Spammer *rausgeklingelt*! 🔔", | |
"🤖 Error 418: I'm a teapot... and you're banned! Spam *abgelehnt*! 🫖", | |
"😂 LOL! Dachte der Spammer echt, das klappt? User *ausgelacht* & gebannt! 🥳", | |
"🍻 Anstoßen! Auf weniger Spam! User hat *Hausverbot*! ✨", | |
"🧐 Debugging complete! Spam-Bug (User) *removed*! Code clean. ✅", | |
"💾 Format C: für den Spammer-Account! Daten *gelöscht*, User gebannt! 😉", | |
"🔌 Netzwerk-Admin sagt: Nein! Spam-Traffic *blockiert*, User gebannt! 🚫", | |
"🖱️ Drag & Drop -> Ban-Liste! Spammer *verschoben*! 😎", | |
"👾 Level Up! Spam-Boss besiegt! User *gebannt*, +100 XP für den Chat! ✨", | |
"☁️ Upload to Ban-Cloud successful! User *archiviert*! ✅", | |
"🔐 Tresor zugeschlagen! Spam kommt hier nicht rein! User *ausgesperrt*! 🛡️", | |
"💥 Krach! Der Banhammer hat gesprochen! User *plattgemacht*! 😎", | |
"🧹 Frühjahrsputz! Der Chat glänzt wieder. Spam & User *entsorgt*! ✨", | |
"🛡️ Undurchdringlich! Unsere Spam-Abwehr hält! User *abgeprallt* & gebannt! 🚫", | |
"🚫 Zutritt verweigert! Dieser Bereich ist spamfrei. User *geblockt*! ✅", | |
"🚨 Achtung, Achtung! Eine Spam-Durchsage: User wurde *gebannt*! Ruhe im Karton! 👍", | |
"⚡️ Hochspannung! Berühren von Spam-Links führt zum Bann! User hat's *erwischt*! ⚡️", | |
"🗑️ Recyclinghof Chat: Spam *getrennt*, User *verwertet* (gebannt)! ♻️", | |
"✌️ Wave goodbye to the spammer! Link war *lame*. Chat bleibt fresh! 😎", | |
"🎉 Party! Aber ohne Spam. User wurde *ausgeladen* (gebannt)! 🥳", | |
"🎯 Ins Schwarze getroffen! Spam erkannt, User *neutralisiert*! ✅", | |
"🎓 Abschlussarbeit: 'Die Effektivität des Banhammers'. Note: 1,0. User *gebannt*! 📝", | |
"🤓 Theorem: Spam = Bann. Beweis: Dieser User. Q.E.D. *Gebannt*! 🧐", | |
"🧐 Falsche Formel angewendet! Spam + Chat ≠ Erfolg. User *rausgerechnet*! 🧮", | |
"📚 Bibliothek der gebannten User hat Zuwachs bekommen! *Einsortiert*! 😉", | |
"🏛️ Hausmeister hat den Spam *rausgekehrt*! User gleich mit! Besenrein! 🧹", | |
" Mensa-Essen war besser als dieser Link! User *abserviert* & gebannt! 🍽️", | |
"📈 Chat-Qualität +1! Spam-User -1! *Optimiert*! ✨", | |
"💡 Lichtschalter umgelegt! Für den Spammer ist's jetzt *dunkel*. Gebannt! 🚫", | |
" Aachener Dom steht stabiler als dieser Spam-Versuch! User *eingestürzt* (gebannt)! ⛪", | |
"⏰ 5 vor 12 für den Spammer! Jetzt ist's zu spät. *Gebannt*! 🕰️", | |
"🤖 Künstliche Intelligenz sagt: Spam = schlecht. User = *gebannt*. Logisch! ✅", | |
"😂 Epic Fail! Der Spam-Versuch war *cringe*. User gebannt! 🤦", | |
"🍻 Zum Wohl! Auf die Admins, die den Bot nutzen! Spammer *weggespült*! ✨", | |
"🧐 Code Review: Spam-Code -> Reject! User -> *Ban*! Merge denied! 🚫", | |
"💾 Backup erstellt? Gut. Spammer-Account wird jetzt *gelöscht*! 😉", | |
"🔌 Kabel durchgeschnitten! Keine Verbindung für den Spammer mehr! *Getrennt* & gebannt! ✂️", | |
"🖱️ Doppelklick auf den Ban-Button! Sicher ist sicher. User *weg*! 😎", | |
"👾 Cheat code activated: /ban_spammer! User *eliminiert*! Level complete! ✨", | |
"☁️ Evicted from the cloud! Spammer *rausgeworfen*! ☁️🚫", | |
"🔐 Schloss ausgetauscht! Neuer Schlüssel passt nicht für Spammer! *Ausgesperrt*! 🔑", | |
] | |
# --- Basic Setup --- | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
# Initialize bot and dispatcher | |
try: | |
bot = Bot(token=API_TOKEN) | |
dp = Dispatcher() | |
except Exception as e: | |
logger.critical(f"Failed to initialize bot: {e}") | |
exit() | |
# --- Helper Function: Check if User is Admin --- | |
async def is_admin(chat_id: int, user_id: int) -> bool: | |
"""Checks if a user is an admin or creator in the chat.""" | |
try: | |
member: ChatMember = await bot.get_chat_member(chat_id, user_id) | |
is_adm = member.status in [ | |
ChatMemberStatus.ADMINISTRATOR, | |
ChatMemberStatus.CREATOR, | |
] | |
# logger.debug( # Reduced logging level for less noise | |
# f"[is_admin] User {user_id} in chat {chat_id} status: {member.status} -> Is Admin: {is_adm}" | |
# ) | |
return is_adm | |
except TelegramAPIError as e: | |
# Handle specific API errors, e.g., bot not in chat or insufficient rights | |
logger.error( | |
f"[is_admin] API Error checking admin status for user {user_id} in chat {chat_id}: {e}" | |
) | |
return False # Assume not admin if we can't check | |
except Exception as e: | |
logger.error( | |
f"[is_admin] Generic Error checking admin status for user {user_id} in chat {chat_id}: {e}" | |
) | |
return False # Assume not admin on other errors | |
# --- Core Logic: Handle Telegram Links from Non-Admins --- | |
# Trigger on text messages in groups and supergroups | |
@dp.message( | |
F.text, | |
F.chat.type.in_({ChatType.GROUP, ChatType.SUPERGROUP}) | |
) | |
async def handle_telegram_links(message: Message): | |
""" | |
Handles text messages in groups/supergroups. | |
If a non-admin posts a t.me or telegram.me link: | |
1. Deletes the message containing the link. | |
2. Bans the user who posted it. | |
3. Notifies admins via PM. | |
4. Posts a celebratory message in the group. | |
""" | |
user = message.from_user | |
chat = message.chat | |
text = message.text or "" | |
# Should not happen for normal messages, but good practice to check | |
if not user: | |
logger.warning(f"Received message without user info in chat {chat.id}") | |
return | |
user_id = user.id | |
chat_id = chat.id | |
message_id = message.message_id | |
user_info = f"{user.full_name} (ID: {user_id})" | |
chat_info = f"{chat.title} (ID: {chat_id})" if chat.title else f"Chat (ID: {chat_id})" | |
logger.info( | |
f"Processing message {message_id} from {user_info} in {chat_info}" | |
) | |
# 1. Check if user is an admin - Admins are immune | |
if await is_admin(chat_id, user_id): | |
logger.info(f"User {user_info} is an admin in {chat_info}. Skipping link check.") | |
return | |
# 2. Check for Telegram links (case-insensitive) | |
# Using word boundaries (\b) to avoid matching parts of other words/URLs | |
# Making it slightly more robust against tricks like t . me / etc. by removing spaces first | |
text_no_spaces = text.replace(" ", "") | |
if re.search(r"\b(t\.me|telegram\.me)/", text_no_spaces, re.IGNORECASE): | |
logger.warning( | |
f"Detected Telegram link from non-admin {user_info} in {chat_info}. Message ID: {message_id}. Text: '{text}'" | |
) | |
# --- Take Action --- | |
action_log = [] | |
delete_success = False | |
ban_success = False | |
# 3. Delete the offending message | |
try: | |
await bot.delete_message(chat_id, message_id) | |
logger.info( | |
f"Successfully deleted message {message_id} from {user_info} in {chat_info}." | |
) | |
action_log.append("✅ Message deleted.") | |
delete_success = True | |
except TelegramAPIError as e: | |
logger.error( | |
f"Failed to delete message {message_id} in {chat_info}: {e}" | |
) | |
action_log.append("❌ Failed to delete message (check bot permissions?).") | |
except Exception as e: | |
logger.error( | |
f"Unexpected error deleting message {message_id} in {chat_info}: {e}" | |
) | |
action_log.append("❌ Unexpected error deleting message.") | |
# 4. Ban the user | |
try: | |
# Ban permanently, don't delete history (optional: revoke_messages=True) | |
await bot.ban_chat_member(chat_id=chat_id, user_id=user_id) | |
logger.info( | |
f"Successfully banned user {user_info} in {chat_info}." | |
) | |
action_log.append("✅ User banned.") | |
ban_success = True | |
except TelegramAPIError as e: | |
logger.error(f"Failed to ban user {user_info} in {chat_info}: {e}") | |
action_log.append("❌ Failed to ban user (check bot permissions?).") | |
except Exception as e: | |
logger.error(f"Unexpected error banning user {user_info} in {chat_info}: {e}") | |
action_log.append("❌ Unexpected error banning user.") | |
# Only proceed with notifications if at least one action was attempted | |
if not action_log: | |
logger.warning(f"No actions attempted for user {user_info} in {chat_info}, skipping notifications.") | |
return | |
# 5. Notify Admins via PM | |
admin_notification = ( | |
f"🚨 **Action Taken in {chat.title or 'Unknown Chat'}** (`{chat_id}`) 🚨\n\n" | |
f"👤 **User:** {user.full_name} (`{user_id}`)\n" | |
f"📜 **Reason:** Posted a Telegram link (`t.me/...` or `telegram.me/...`)\n" | |
f"💬 **Message Text (deleted):** ```\n{text}\n```\n" | |
f"🛠️ **Actions Taken:**\n- {action_log[0]}" | |
) | |
if len(action_log) > 1: | |
admin_notification += f"\n- {action_log[1]}" | |
try: | |
admins = await bot.get_chat_administrators(chat_id) | |
admin_ids_notified = set() # Avoid duplicate notifications if user is admin multiple ways | |
for admin in admins: | |
# Don't notify the bot itself or other bots | |
if not admin.user.is_bot and admin.user.id not in admin_ids_notified: | |
try: | |
await bot.send_message( | |
admin.user.id, | |
admin_notification, | |
parse_mode="Markdown", | |
) | |
admin_ids_notified.add(admin.user.id) | |
# logger.debug( # Reduce log noise | |
# f"Notified admin {admin.user.id} about action against {user_id}." | |
# ) | |
except TelegramAPIError as e_pm: | |
# Common errors: bot blocked by admin, chat not found (user deleted account?) | |
logger.warning( | |
f"Failed to send PM notification to admin {admin.user.id} (User: {admin.user.full_name}): {e_pm}" | |
) | |
except Exception as e_pm_other: | |
logger.warning( | |
f"Unexpected error sending PM to admin {admin.user.id}: {e_pm_other}" | |
) | |
logger.info(f"Attempted PM notifications to {len(admin_ids_notified)} admins for action against {user_info}.") | |
except TelegramAPIError as e_admins: | |
logger.error( | |
f"Failed to get admin list for chat {chat_info}: {e_admins}" | |
) | |
except Exception as e_admins_other: | |
logger.error( | |
f"Unexpected error getting admin list for {chat_info}: {e_admins_other}" | |
) | |
# 6. Post celebratory message in the group (only if ban was successful) | |
if ban_success: | |
celebration = random.choice(CELEBRATORY_PHRASES) | |
try: | |
# Use Markdown for potential formatting in phrases | |
# Mentioning the user clearly | |
user_mention_md = f"User '{user.full_name}' (`{user_id}`)" | |
await bot.send_message( | |
chat_id, | |
f"{celebration}\n_({user_mention_md} was banned for posting a Telegram link.)_", | |
parse_mode="Markdown" | |
) | |
logger.info( | |
f"Posted celebratory message in {chat_info} for banning {user_info}." | |
) | |
except TelegramAPIError as e_group_msg: | |
logger.error( | |
f"Failed to send celebratory message to {chat_info}: {e_group_msg}" | |
) | |
except Exception as e_group_msg_other: | |
logger.error( | |
f"Unexpected error sending celebratory message to {chat_info}: {e_group_msg_other}" | |
) | |
else: | |
logger.warning(f"Skipping celebratory message in {chat_info} because ban failed for {user_info}.") | |
else: | |
# This message is logged for every non-admin message without a link, might be noisy | |
# logger.debug( | |
# f"Message from non-admin {user_info} in {chat_info} does not contain a Telegram link. No action needed." | |
# ) | |
pass # No action needed if no link is found | |
# --- Simple Start Command (Optional) --- | |
@dp.message(Command(commands=["start"])) | |
async def send_welcome(message: Message): | |
"""Sends a simple welcome message when /start is used in private chat.""" | |
if message.chat.type == ChatType.PRIVATE: | |
await message.reply("Hallo! Ich bin der Link-Filter-Bot. Füge mich zu einer Gruppe hinzu, um Telegram-Link-Spam von Nicht-Admins zu bekämpfen!") | |
# No reply needed in groups for /start | |
# --- Main Function --- | |
async def main(): | |
logger.info( | |
"Starting simplified Telegram link filter bot (aiogram v3)..." | |
) | |
# Start polling - this listens for updates from Telegram | |
await dp.start_polling(bot) | |
if __name__ == "__main__": | |
# --- IMPORTANT SECURITY WARNING --- | |
# Replace the hardcoded API_TOKEN above with a secure method | |
# like environment variables before deploying! | |
# Example using environment variable: | |
# API_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") | |
# if not API_TOKEN: | |
# logger.critical("FATAL: TELEGRAM_BOT_TOKEN environment variable not set!") | |
# exit(1) | |
# bot = Bot(token=API_TOKEN) # Initialize bot after getting token | |
if "YOUR_BOT_TOKEN_HERE" in API_TOKEN or len(API_TOKEN) < 40: # Basic check | |
logger.critical("!!! CRITICAL: Please replace the placeholder API_TOKEN with your actual bot token. !!!") | |
logger.critical("Bot will not start.") | |
else: | |
try: | |
asyncio.run(main()) | |
except KeyboardInterrupt: | |
logger.info("Bot stopped manually.") | |
except Exception as e: | |
logger.critical(f"Bot crashed with unexpected error: {e}") | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
aiogram |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
:D