__version__ = (0, 1, 34)
# ▄▀█ █▄ █ █▀█ █▄ █ █▀█ ▀▀█ █▀█ █ █ █▀
# █▀█ █ ▀█ █▄█ █ ▀█ ▀▀█ █ ▀▀█ ▀▀█ ▄█
#
# © Copyright 2024
#
# developed by @anon97945
#
# https://t.me/apodiktum_modules
# https://github.com/anon97945
#
# 🔒 Licensed under the GNU GPLv3
# 🌐 https://www.gnu.org/licenses/gpl-3.0.html
# meta developer: @apodiktum_modules
# meta banner: https://t.me/apodiktum_dumpster/11
# meta pic: https://t.me/apodiktum_dumpster/13
# scope: hikka_only
# scope: hikka_min 1.3.3
import asyncio
import contextlib
import logging
from telethon.tl.types import Message
from telethon.hints import EntityLike
from .. import loader, utils
logger = logging.getLogger(__name__)
def represents_int(s: str) -> bool:
try:
loader.validators.Integer().validate(s)
return True
except loader.validators.ValidationError:
return False
@loader.tds
class ApodiktumPurgeMod(loader.Module):
"""
Userbot module for purging unneeded messages(usually spam or ot).
Check the `.config apodiktum purge` to enable/disable logging.
"""
strings = {
"name": "Apo-Purge",
"developer": "@anon97945",
"_cfg_log_edit": "Log `edit` as info.",
"_cfg_log_purge": "Log purge `count` as info.",
"_cfg_log_purgeme": "Log `purgeme `count as info.",
"_cfg_log_sd": "Log `sd` as info.",
"edit_success": (
"Edit done successfully.\nOld message:\n{}\n\n\nNew message:\n{}"
),
"err_cmd_wrong": "Your command was wrong.",
"err_purge_start": "Please reply to a message to start purging.",
"no_int": "Your input was no integer.",
"permerror": "You don't have permission to use this command.",
"purge_cmpl": "Purge complete!\nPurged {} messages.",
"purge_success": "Purge of {} messages done successfully.",
"sd_success": "Message after {} seconds successfully deleted.",
"_cfg_cst_auto_migrate": "Wheather to auto migrate defined changes on startup.",
}
strings_en = {}
strings_de = {
"_cfg_log_edit": "Protokollieren Sie `edit` Nachrichten als Info.",
"_cfg_log_purge": (
"Protokollieren Sie die Anzahl der `purge` Nachrichten als Info."
),
"_cfg_log_purgeme": (
"Protokollieren Sie die Anzahl der `purgeme` Nachrichten als Info."
),
"_cfg_log_sd": "Protokollieren `self-destructive` Nachrichten als Info.",
"_cls_doc:": (
"Module zum entfernen von Nachrichten(normalerweise spam,"
" etc.).\nCheck `.config apodiktum purge` um das Protokollieren zu"
" aktivieren/deaktivieren."
),
"_cmd_doc_cpurge": "Dadurch wird die Konfiguration für das Modul geöffnet.",
"_cmd_doc_del": (
"Löscht die beantwortete Nachricht.\n- Verwendung: .adel "
),
"_cmd_doc_edit": (
"Bearbeitet die letzte Nachricht.\n- Verwendung: .edit "
),
"_cmd_doc_purge": (
"Löscht alle Nachrichten bis zu und inklusive der Antwort.\n"
"- Verwendung: .apurge "
),
"_cmd_doc_purgeme": (
"Löscht x (oder alle) Nachrichten von dir.\n"
"- Verwendung: .purgeme "
),
"_cmd_doc_purgeuser": (
"Löscht alle Nachrichten von einem Nutzer.\n"
"- Verwendung: .purgeuser "
),
"_cmd_doc_sd": (
"Löscht die letzte Nachricht nach x Sekunden. Funktioniert auch mit"
" Medien.\nVerwendung: .sd "
),
"_cmd_doc_spurge": (
"Löscht alle Nachrichten bis zu und inklusive der Antwort ohne"
" Benachrichtigung.\n- Verwendung: .spurge "
),
"_cmd_doc_spurgeme": (
"Löscht x (oder alle) Nachrichten von dir ohne Benachrichtigung.\n"
"- Verwendung: .spurgeme "
),
"_cmd_doc_spurgeuser": (
"Löscht alle Nachrichten von einem Nutzer ohne Benachrichtigung.\n"
"- Verwendung: .spurgeuser "
),
"edit_success": (
"Bearbeitung erfolgreich.\nAlte Nachricht:\n{}\n\n\nNeue Nachricht:\n{}"
),
"err_cmd_wrong": "Deine Eingabe war falsch.",
"err_purge_start": (
"Bitte antworte auf eine Nachricht, um die Löschung zu starten."
),
"no_int": "Dein Eingabe war kein Integer.",
"permerror": "Du hast keine Berechtigung, diesen Befehl zu verwenden.",
"purge_cmpl": (
"Purge fertig!\n{} Nachrichten wurden gelöscht."
),
"purge_success": "Löschung von {} Nachrichten erfolgreich durchgeführt.",
"sd_success": "Nachricht nach {} Sekunden erfolgreich gelöscht.",
}
strings_ru = {
"_cfg_log_edit": "Логировать редактирование сообщения как info.",
"_cfg_log_purge": "Логировать количество очищенных сообщений как info.",
"_cfg_log_purgeme": (
"Логировать количество удаленных сообщений от вас как info."
),
"_cfg_log_sd": "Логировать создание сообщения как info.",
"_cls_doc": (
"Модуль для очистки спама и т.д.Проверьте `.config apodiktum"
" purge`, чтобы включить/выключить ведение журнала."
),
"_cmd_doc_cpurge": "Это откроет конфиг для модуля.",
"_cmd_doc_edit": (
"Редактирует последнее сообщение.\n- Использование: .aedit <сообщение>"
),
"_cmd_doc_purge": (
"Удаляет все сообщения до и включая ответ.\n"
"- Использование: .apurge <реплай>"
),
"_cmd_doc_purgeme": (
"Удаляет x (или все) сообщений от вас.\n"
"- Использование: .purgeme <количество/все>"
),
"_cmd_doc_purgeuser": (
"Удаляет все сообщения от определенного пользователя.\n"
"- Использование: .purgeuser <реплай>"
),
"_cmd_doc_sd": (
"Удаляет последнее сообщение через x секунд.\n"
"- Использование: .sd <секунды> <сообщение>"
),
"_cmd_doc_spurge": (
"Удаляет все сообщения до и включая ответ без оповещения.\n"
"- Использование: .spurge <реплай>"
),
"_cmd_doc_spurgeme": (
"Удаляет x (или все) сообщений от вас без оповещения.\n"
"- Использование: .spurgeme <количество/все>"
),
"_cmd_doc_spurgeuser": (
"Удаляет все сообщения от определенного пользователя без"
" оповещения.\n- Использование: .spurgeuser <реплай>"
),
"edit_success": (
"Редактирование завершено успешно.\n"
"Старое сообщение:\n{}\n\n\nНовое сообщение:\n{}"
),
"err_cmd_wrong": "Ваш команда была неверной.",
"err_purge_start": (
"Пожалуйста, ответьте на сообщение для начала очистки."
),
"no_int": "Введенное значение не является целым числом (int)",
"permerror": "У вас недостаточно прав для использования этой команды.",
"purge_cmpl": "Очистка завершена!\nОчищено {} сообщений.",
"purge_success": "Очистка {} сообщений завершена успешно.",
"sd_success": "Сообщение после {} секунд успешно удалено.",
}
all_strings = {
"strings": strings,
"strings_en": strings,
"strings_de": strings_de,
"strings_ru": strings_ru,
}
changes = {
"migration1": {
"name": {
"old": "Apo Purge",
"new": "Apo-Purge",
},
},
}
def __init__(self):
self._ratelimit = []
self.config = loader.ModuleConfig(
loader.ConfigValue(
"log_edit",
False,
doc=lambda: self.strings("_cfg_log_edit"),
validator=loader.validators.Boolean(),
),
loader.ConfigValue(
"log_purge",
False,
doc=lambda: self.strings("_cfg_log_purge"),
validator=loader.validators.Boolean(),
),
loader.ConfigValue(
"log_purgeme",
False,
doc=lambda: self.strings("_cfg_log_purgeme"),
validator=loader.validators.Boolean(),
),
loader.ConfigValue(
"log_sd",
False,
doc=lambda: self.strings("_cfg_log_sd"),
validator=loader.validators.Boolean(),
),
loader.ConfigValue(
"auto_migrate",
True,
doc=lambda: self.strings("_cfg_cst_auto_migrate"),
validator=loader.validators.Boolean(),
), # for MigratorClass
)
async def client_ready(self):
self.apo_lib = await self.import_lib(
"https://raw.githubusercontent.com/anon97945/hikka-libs/master/apodiktum_library.py",
suspend_on_error=True,
)
await self.apo_lib.migrator.auto_migrate_handler(
self.__class__.__name__,
self.strings("name"),
self.changes,
self.config["auto_migrate"],
)
async def _purge_user_messages(
self,
chat: EntityLike,
user_id: int,
purge_count: int,
) -> int:
msgs = []
msg_count = 0
itermsg = self._client.iter_messages(entity=chat)
if purge_count == "all":
async for msg in itermsg:
if msg.sender_id == user_id:
msgs += [msg.id]
msg_count += 1
if len(msgs) >= 99:
await self._client.delete_messages(chat, msgs)
msgs.clear()
else:
i = 0
async for msg in itermsg:
if msg.sender_id == user_id:
if i == purge_count:
break
i += 1
msgs += [msg.id]
msg_count += 1
if len(msgs) >= 99:
await self._client.delete_messages(chat, msgs)
msgs.clear()
if msgs:
await self._client.delete_messages(chat, msgs)
return msg_count
async def _purge_messages(
self,
chat: EntityLike,
self_id: int,
can_delete: bool,
message: Message,
) -> int:
msg_count = 0
itermsg = self._client.iter_messages(
entity=chat,
min_id=message.reply_to_msg_id,
reverse=True,
)
msgs = [message.reply_to_msg_id]
async for msg in itermsg:
if can_delete:
msgs.append(msg)
msg_count += 1
elif msg.sender_id == self_id:
msgs.append(msg)
if msg.id != message.id:
msg_count += 1
if len(msgs) >= 99:
await self._client.delete_messages(chat, msgs)
msgs.clear()
if msgs:
await self._client.delete_messages(chat, msgs)
return msg_count
async def cpurgecmd(self, message: Message):
"""
This will open the config for the module.
"""
name = self.strings("name")
await self.allmodules.commands["config"](
await utils.answer(message, f"{self.get_prefix()}config {name}")
)
async def apurgecmd(self, message: Message):
"""
Delete all messages up to and including the reply.
- Usage: .apurge
"""
chat = message.chat
if message.reply_to_msg_id is not None:
can_delete = bool(
message.is_private
or (
(chat.admin_rights or chat.creator)
and chat.admin_rights.delete_messages
or chat.admin_rights
and chat.creator
)
)
msg_count = await self._purge_messages(
chat, self.tg_id, can_delete, message
)
else:
await utils.answer(
message,
self.apo_lib.utils.get_str(
"err_purge_start", self.all_strings, message
),
)
return
done = await self._client.send_message(
chat.id,
self.apo_lib.utils.get_str("purge_cmpl", self.all_strings, message).format(
msg_count
),
)
await asyncio.sleep(2)
await done.delete()
if self.config["log_purge"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def spurgecmd(self, message: Message):
"""
Delete all messages up to and including the reply silently.
- Usage: .spurge
"""
chat = message.chat
if message.reply_to_msg_id is not None:
can_delete = bool(
message.is_private
or (
(chat.admin_rights or chat.creator)
and chat.admin_rights.delete_messages
or chat.admin_rights
and chat.creator
)
)
msg_count = await self._purge_messages(
chat,
self.tg_id,
can_delete,
message,
)
else:
await utils.answer(
message,
self.apo_lib.utils.get_str(
"err_purge_start",
self.all_strings,
message,
),
)
return
if self.config["log_purge"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def purgemecmd(self, message: Message):
"""
Delete x count (or all) of your latest messages.
- Usage: .purgeme
"""
chat = message.chat
args = utils.get_args_raw(message).lower()
args = str(args).split()
if not represents_int(args[0]) and "all" not in args:
await utils.answer(
message,
self.apo_lib.utils.get_str("no_int", self.all_strings, message),
)
return
if len(args) > 1:
await utils.answer(
message,
self.apo_lib.utils.get_str("err_cmd_wrong", self.all_strings, message),
)
return
purge_count = "all" if len(args) == 1 and "all" in args else int(args[0])
user_id = self.tg_id
await message.delete()
msg_count = await self._purge_user_messages(chat, user_id, purge_count)
done = await self._client.send_message(
chat.id,
self.apo_lib.utils.get_str("purge_cmpl", self.all_strings, message).format(
str(msg_count)
),
)
await asyncio.sleep(2)
await done.delete()
if self.config["log_purgeme"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def spurgemecmd(self, message: Message):
"""
Delete x count (or all) of your latest messages silently.
- Usage: .spurgeme
"""
chat = message.chat
args = utils.get_args_raw(message).lower()
args = str(args).split()
if not represents_int(args[0]) and "all" not in args:
await utils.answer(
message,
self.apo_lib.utils.get_str("no_int", self.all_strings, message),
)
return
if len(args) > 1:
await utils.answer(
message,
self.apo_lib.utils.get_str("err_cmd_wrong", self.all_strings, message),
)
return
purge_count = "all" if len(args) == 1 and "all" in args else int(args[0])
user_id = self.tg_id
await message.delete()
msg_count = await self._purge_user_messages(chat, user_id, purge_count)
if self.config["log_purgeme"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def purgeusercmd(self, message: Message):
"""
Delete all messages from the replied user.
- Usage: .purgeuser
"""
chat = message.chat
if not message.is_reply:
return await utils.answer(
message,
self.apo_lib.utils.get_str("no_reply", self.all_strings, message),
)
reply = await message.get_reply_message()
user_id = reply.sender_id
if (
(chat.admin_rights or chat.creator)
and not chat.admin_rights.delete_messages
or not chat.admin_rights
and not chat.creator
):
return await utils.answer(
message,
self.apo_lib.utils.get_str("permerror", self.all_strings, message),
)
purge_count = "all"
await message.delete()
msg_count = await self._purge_user_messages(chat, user_id, purge_count)
done = await self._client.send_message(
chat.id,
self.apo_lib.utils.get_str("purge_cmpl", self.all_strings, message).format(
str(msg_count)
),
)
await asyncio.sleep(2)
await done.delete()
if self.config["log_purgeme"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def spurgeusercmd(self, message: Message):
"""
Delete all messages from the replied user silently.
- Usage: .spurgeuser
"""
chat = message.chat
if not message.is_reply:
return await utils.answer(
message,
self.apo_lib.utils.get_str("no_reply", self.all_strings, message),
)
reply = await message.get_reply_message()
user_id = reply.sender_id
if (
(chat.admin_rights or chat.creator)
and not chat.admin_rights.delete_messages
or not chat.admin_rights
and not chat.creator
):
return await utils.answer(
message,
self.apo_lib.utils.get_str("permerror", self.all_strings, message),
)
purge_count = "all"
await message.delete()
msg_count = await self._purge_user_messages(chat, user_id, purge_count)
if self.config["log_purgeme"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("purge_success").format(str(msg_count)),
)
async def adelcmd(self, message: Message):
"""
Delete the replied message.
- Usage: .adel
"""
reply = await message.get_reply_message()
if reply:
with contextlib.suppress(Exception):
await reply.delete()
await message.delete()
async def editcmd(self, message: Message):
"""
Edit your last message.
- Usage: .edit
"""
chat = message.chat
args = utils.get_args_raw(message)
if not args:
await utils.answer(
message,
self.apo_lib.utils.get_str("err_cmd_wrong", self.all_strings, message),
)
return
i = 1
async for msg in self._client.iter_messages(chat):
if msg.out:
if i == 2:
old_msg = self.apo_lib.utils.raw_text(msg)
new_msg = args
await msg.edit(new_msg)
await message.delete()
break
i += 1
if self.config["log_edit"]:
self.apo_lib.utils.log(
logging.INFO,
__name__,
self.strings("edit_success").format(old_msg, new_msg),
)
async def sdcmd(self, message: Message):
"""
Make self-destructive messages. Also works for media when used in caption.
- Usage: .sd