Skip to content

Instantly share code, notes, and snippets.

@SpotlightForBugs
Created April 4, 2025 22:26
Show Gist options
  • Save SpotlightForBugs/efd569b6adbebd8cfe123ec888df1356 to your computer and use it in GitHub Desktop.
Save SpotlightForBugs/efd569b6adbebd8cfe123ec888df1356 to your computer and use it in GitHub Desktop.
Telegram bot that removes non-admin invite link messages
#!/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}")
@SpotlightForBugs
Copy link
Author

:D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment