Кружки в чатах — это прекрасно, ведь они добавляют общению иммерсивности. Да только одно дело, когда кружки отправляет кто-то, от кого вы их ждете. Например, Юрьевич. И совсем другое, когда кто-то ими спамит 24/7. Конечно, кружки всегда можно отключить. Но что если вы хотите отключать их не у всех, а только у спамеров? Тут-то и приходит на помощь наш бот.
Какие задачи решает бот, добавляющий в ЧС за кружки
Из названия очевидно — добавляет в ЧС за отправку кружков. Но как он тогда понимает, кому можно отправлять кружки, а кому нельзя? Все просто: по умолчанию нельзя всем. Даже вам, но бот не сможет вас забанить, если вы админ и не выдали ему права на бан админов. Но есть белый список, и тем, кто в него внесен, отправлять кружки можно. Их бот трогать не будет. Для чего это нужно? Ну например, для:
Борьбы со спамерами.
Чтобы не потерять ни один кружок от Е. Ю.
Чтоб оставить возможность отправки кружков только тем, кому вы готовы ее предоставить. Например, сотрудникам вашей партнерки, если речь про чат ПП.
А в целом для чего придумаете, для того и нужно. Каких-то ограничений, «пляшущих» от ситуации, у бота нет.
Принцип работы бота для добавления в ЧС за кружки
С точки зрения алгоритма он тоже несложный и делает вот что:
- Слушает эфир.
- Автоматически создает папку whitelist (если ее еще нет) и .txt с ID чата в имени (если такого еще нет) для хранения списка тех, кому можно отправлять кружки, по триггеру — любое сообщение в чате (где бот админ).
- При обнаружении сообщений с кружком — удаляет его и банит отправителя, если его ID отсутствует в .txt, хранящем список тех, кому можно отправлять кружки в данном чате.
- При получении в ЛС какого-либо сообщения проверяет, есть ли его отправить в списке админов (список вшит в код для безопасности). Если нет — игнорирует. Если да — реагирует на команды.
- При вводе /list — выводит список чатов, для которых подключен БС.
- При вводе /all — «выбирает» все чаты.
- При вводе /set ID чата — «выбирает» указанный чат.
- При вводе /add ID юзера — добавляет юзера в БС выбранного чата.
- При вводе /del ID юзера — удаляет юзера из БС выбранного чата.
- Выводит сервисные сообщения о банах в консоль — для дополнительного мониторинга.
Как видите, все просто.
Пошаговая инструкция, как сделать бот для добавления в ЧС за кружки
Не сложно и создать данный бот. Но сначала нужно настроить сервак для работы с Телегой (север должен поддерживать Python). Если у вас такого нет — здесь способ развернуть такой бесплатно на своем ПК. Но в целом сгодится и арендный (вообще он предпочтительнее — вы же не будете гонять домашний ПК 24/7). Затем в консоль сервера пишем:
pip install aiogram
После этого делаем следующее:
1. Пишем в ЛС BotFather — и получаем токен для нашего бота.
2. В корневом каталоге сервера создаем bot.py
3. Открываем в текстовом редакторе и копируем в него:
import asyncio
import os
from aiogram import Bot, Dispatcher, F
from aiogram.types import Message
from aiogram.filters import Command
TOKEN = "ВАШ ТОКЕН"
CONTROL_USERS = {ВАШ ID,}
WHITELIST_DIR = "whitelists"
os.makedirs(WHITELIST_DIR, exist_ok=True)
bot = Bot(token=TOKEN)
dp = Dispatcher()
selected_chat: dict[int, str] = {}
def whitelist_path(chat_id: str) -> str:
return os.path.join(WHITELIST_DIR, f"{chat_id}.txt")
def ensure_whitelist_exists(chat_id: str):
path = whitelist_path(chat_id)
if not os.path.exists(path):
open(path, "w", encoding="utf-8").close()
def load_whitelist(chat_id: str) -> set[int]:
ensure_whitelist_exists(chat_id)
with open(whitelist_path(chat_id), "r", encoding="utf-8") as f:
return {int(line.strip()) for line in f if line.strip().isdigit()}
def save_whitelist(chat_id: str, data: set[int]):
ensure_whitelist_exists(chat_id)
with open(whitelist_path(chat_id), "w", encoding="utf-8") as f:
for uid in sorted(data):
f.write(f"{uid}\n")
def get_all_chats() -> list[str]:
return sorted(
f.replace(".txt", "")
for f in os.listdir(WHITELIST_DIR)
if f.endswith(".txt")
)
def is_control_user(user_id: int) -> bool:
return user_id in CONTROL_USERS
async def ensure_chat_registered(message: Message):
if message.chat.type in {"group", "supergroup"}:
try:
member = await bot.get_chat_member(message.chat.id, bot.id)
if member.status in {"administrator", "creator"}:
ensure_whitelist_exists(str(message.chat.id))
except Exception:
pass
@dp.message(F.video_note, F.chat.type.in_({"group", "supergroup"}))
async def handle_video_note(message: Message):
user = message.from_user
if not user:
return
chat_id = message.chat.id
whitelist = load_whitelist(str(chat_id)) # загружаем из файла
if user.id in whitelist:
return
try:
await bot.ban_chat_member(chat_id=chat_id, user_id=user.id)
await message.delete()
print(f"[BAN] {user.id} в чате {chat_id}")
except Exception as e:
print(f"[ERROR BAN] {e}")
@dp.message(F.chat.type.in_({"group", "supergroup"}))
async def any_message_hook(message: Message):
await ensure_chat_registered(message)
@dp.message(Command("list"), F.chat.type == "private")
async def cmd_list(message: Message):
if not is_control_user(message.from_user.id):
return
chats = get_all_chats()
if not chats:
await message.answer("Чаты ещё не обнаружены")
return
text = ["Чаты с whitelist:"]
for chat_id in chats:
wl = load_whitelist(chat_id)
text.append(f"{chat_id} — {len(wl)} ID")
await message.answer("\n".join(text))
@dp.message(Command("set"), F.chat.type == "private")
async def cmd_set(message: Message):
if not is_control_user(message.from_user.id):
return
parts = message.text.split()
if len(parts) != 2:
await message.answer("Использование:\n/set <chat_id>")
return
chat_id = parts[1]
ensure_whitelist_exists(chat_id)
selected_chat[message.from_user.id] = chat_id
await message.answer(f"Выбран чат:\n{chat_id}")
@dp.message(Command("all"), F.chat.type == "private")
async def cmd_all(message: Message):
if not is_control_user(message.from_user.id):
return
selected_chat[message.from_user.id] = "ALL"
await message.answer("Выбраны все чаты")
@dp.message(Command("add"), F.chat.type == "private")
async def cmd_add(message: Message):
if not is_control_user(message.from_user.id):
return
parts = message.text.split()
if len(parts) != 2 or not parts[1].isdigit():
await message.answer("Использование:\n/add <user_id>")
return
uid = int(parts[1])
target = selected_chat.get(message.from_user.id)
if not target:
await message.answer("Сначала выбери чат: /set или /all")
return
chats = get_all_chats() if target == "ALL" else [target]
for chat_id in chats:
wl = load_whitelist(chat_id)
wl.add(uid)
save_whitelist(chat_id, wl)
await message.answer(f"ID {uid} добавлен")
@dp.message(Command("del"), F.chat.type == "private")
async def cmd_del(message: Message):
if not is_control_user(message.from_user.id):
return
parts = message.text.split()
if len(parts) != 2 or not parts[1].isdigit():
await message.answer("Использование:\n/del <user_id>")
return
uid = int(parts[1])
target = selected_chat.get(message.from_user.id)
if not target:
await message.answer("Сначала выбери чат: /set или /all")
return
chats = get_all_chats() if target == "ALL" else [target]
for chat_id in chats:
wl = load_whitelist(chat_id)
wl.discard(uid)
save_whitelist(chat_id, wl)
await message.answer(f"ID {uid} удалён")
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
4. Находим TOKEN = "ВАШ ТОКЕН" и подставляем ваш токен.
5. Находим CONTROL_USERS = {ВАШ ID,} и подставляем ваш ID (или несколько через запятую.
6. Запускаем бот командой python bot.py
7. Проверяем, все ли работает.
Демонстрация работы
Обязательно делаем бота админом в чатах, которые он будет админить, иначе ничего не будет работать.
Все работает.
Подводя итоги
Как видите, банить спамеров кружками, пропуская при этом кружки от Юрьевича, проще, чем кажется. Достаточно быть подписанным на Traffic Cardinal.