fix: improve auto-delete reliability and recent cleanup

This commit is contained in:
sadtweenk
2026-04-20 16:44:47 +03:00
parent d539eab31d
commit bcd6f3e734
2 changed files with 74 additions and 8 deletions

View File

@@ -10,6 +10,7 @@
- Команда разбана: `/РАЗБАН` (тоже можно с `!`). - Команда разбана: `/РАЗБАН` (тоже можно с `!`).
- Обе команды работают только как `reply` на сообщение нужного пользователя. - Обе команды работают только как `reply` на сообщение нужного пользователя.
- Список ID хранится в `data/blocked_users.json` и сохраняется между перезапусками. - Список ID хранится в `data/blocked_users.json` и сохраняется между перезапусками.
- При бане дополнительно чистятся последние сообщения этого пользователя в текущем чате.
## Установка ## Установка
1. Установите Python 3.10+. 1. Установите Python 3.10+.
@@ -35,8 +36,9 @@
## Как пользоваться ## Как пользоваться
1. В группе ответьте на сообщение пользователя командой `/ВБАННАХУЙ!`. 1. В группе ответьте на сообщение пользователя командой `/ВБАННАХУЙ!`.
2. Юзербот покажет короткую анимацию и добавит ID пользователя в автоудаление. 2. Юзербот покажет короткую анимацию и добавит ID пользователя в автоудаление.
3. Новые сообщения этого пользователя в группах будут удаляться только у вас. 3. После бана бот также попробует удалить недавние сообщения этого пользователя в текущем чате.
4. Чтобы отключить автоудаление, ответьте на его сообщение командой `/РАЗБАН`. 4. Новые сообщения этого пользователя в группах будут удаляться только у вас.
5. Чтобы отключить автоудаление, ответьте на его сообщение командой `/РАЗБАН`.
## Ограничения ## Ограничения
- Удаление "только у вас" работает в формате `best effort` и зависит от ограничений Telegram API. - Удаление "только у вас" работает в формате `best effort` и зависит от ограничений Telegram API.

76
bot.py
View File

@@ -7,11 +7,13 @@ from typing import Optional
from dotenv import load_dotenv from dotenv import load_dotenv
from telethon import TelegramClient, events from telethon import TelegramClient, events
from telethon.errors import RPCError
from telethon.tl.custom.message import Message from telethon.tl.custom.message import Message
BAN_COMMAND = "/вбаннахуй" BAN_COMMAND = "/вбаннахуй"
UNBAN_COMMAND = "/разбан" UNBAN_COMMAND = "/разбан"
DATA_PATH = Path("data/blocked_users.json") DATA_PATH = Path("data/blocked_users.json")
RECENT_CLEANUP_LIMIT = 50
ANIMATION_FRAMES = [ ANIMATION_FRAMES = [
"Запускаю анти-режим.", "Запускаю анти-режим.",
@@ -127,6 +129,60 @@ async def animate_ban(message: Message, target_user_id: int, is_new: bool) -> No
logging.exception("Не удалось отправить финальный статус анимации.") logging.exception("Не удалось отправить финальный статус анимации.")
async def delete_message_best_effort(
client: TelegramClient, message: Message
) -> bool:
try:
await message.delete(revoke=False)
return True
except Exception as exc:
logging.debug(
"Удаление через message.delete(revoke=False) не сработало: %s", exc
)
try:
target = message.input_chat if message.input_chat else message.chat_id
await client.delete_messages(target, [message.id], revoke=False)
return True
except Exception as exc:
logging.debug(
"Удаление через client.delete_messages(..., revoke=False) не сработало: %s",
exc,
)
try:
await message.delete()
return True
except RPCError as exc:
logging.warning(
"Не удалось удалить сообщение %s в чате %s: %s",
message.id,
message.chat_id,
exc,
)
except Exception:
logging.exception(
"Неожиданная ошибка удаления сообщения %s в чате %s.",
message.id,
message.chat_id,
)
return False
async def cleanup_recent_messages_from_user(
client: TelegramClient, chat_id: int, user_id: int, limit: int = RECENT_CLEANUP_LIMIT
) -> int:
deleted_count = 0
async for message in client.iter_messages(chat_id, from_user=user_id, limit=limit):
if message.id is None:
continue
if await delete_message_best_effort(client, message):
deleted_count += 1
return deleted_count
def load_settings() -> tuple[int, str, str]: def load_settings() -> tuple[int, str, str]:
load_dotenv() load_dotenv()
api_id_raw = os.getenv("API_ID", "").strip() api_id_raw = os.getenv("API_ID", "").strip()
@@ -181,6 +237,15 @@ async def main() -> None:
status_message = await event.reply("Подготовка...") status_message = await event.reply("Подготовка...")
added = await blocklist.add(target_user_id) added = await blocklist.add(target_user_id)
await animate_ban(status_message, target_user_id, added) await animate_ban(status_message, target_user_id, added)
cleaned = await cleanup_recent_messages_from_user(
client,
event.chat_id,
target_user_id,
)
if cleaned > 0:
await event.reply(
f"Дополнительно очищено последних сообщений в этом чате: {cleaned}."
)
return return
removed = await blocklist.remove(target_user_id) removed = await blocklist.remove(target_user_id)
@@ -196,7 +261,7 @@ async def main() -> None:
@client.on(events.NewMessage(incoming=True)) @client.on(events.NewMessage(incoming=True))
async def auto_delete_target_messages(event: events.NewMessage.Event) -> None: async def auto_delete_target_messages(event: events.NewMessage.Event) -> None:
if not event.is_group: if event.is_private:
return return
sender_id = event.sender_id sender_id = event.sender_id
@@ -206,11 +271,10 @@ async def main() -> None:
if not await blocklist.contains(int(sender_id)): if not await blocklist.contains(int(sender_id)):
return return
try: deleted = await delete_message_best_effort(client, event.message)
await client.delete_messages(event.chat_id, [event.id], revoke=False) if not deleted:
except Exception: logging.warning(
logging.exception( "Пропуск удаления: сообщение %s от пользователя %s в чате %s.",
"Не удалось удалить сообщение %s от пользователя %s в чате %s.",
event.id, event.id,
sender_id, sender_id,
event.chat_id, event.chat_id,