__version__ = (1, 0, 0, 1)
# This file is a part of Hikka Userbot
# Code is NOT licensed under CC-BY-NC-ND 4.0 unless otherwise specified.
# 🌐 https://github.com/hikariatama/Hikka
# You CAN edit this file without direct permission from the author.
# You can redistribute this file with any modifications.
# meta developer: @yg_modules
# scope: hikka_only
# scope: hikka_min 1.6.3
# █▄█ █░█ █▀▄▀█ █▀▄▀█ █▄█ █▀▄▀█ █▀█ █▀▄ █▀
# ░█░ █▄█ █░▀░█ █░▀░█ ░█░ █░▀░█ █▄█ █▄▀ ▄█
import re
from .. import loader, utils
from telethon import events
import os
@loader.tds
class yg_trigger(loader.Module):
"""Триггер-модуль. Документация: kok.gay/trigger"""
strings = {"name": "yg_trigger"}
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"watcher_on",
True,
"состояние вотчера",
validator=loader.validators.Boolean()
)
)
async def client_ready(self, client, db):
self.db = db
self.triggers = self.db.get("triggers", "list", [])
self.client = client
handlers = [
(self.trigger, [events.NewMessage, events.MessageEdited])
]
for handler_func, event_list in handlers:
for event in event_list:
self.client.add_event_handler(handler_func, event)
async def save_triggers(self):
self.db.set("triggers", "list", self.triggers)
async def validate(self, entity_value, target_entity):
entity_k = entity_value.replace("@", "")
entity_id = getattr(target_entity, "id", None)
entity_usernames = await self.get_usernames(target_entity)
if entity_k.isdigit():
return int(entity_value) == entity_id
return entity_k.lower() in entity_usernames
async def add_trigger(self, conditions: dict, response: str):
self.triggers.append({"conditions": conditions, "response": response})
await self.save_triggers()
async def triggercmd(self, message):
"""вкл/выкл вотчер"""
self.config["watcher_on"] = not self.config["watcher_on"]
await message.edit(f"🎮 Триггер-мод {'включен' if self.config['watcher_on'] else 'выключен'}")
async def remove_trigger(self, index: int):
try:
del self.triggers[index]
await self.save_triggers()
return True
except IndexError:
return False
async def clear_triggers(self):
self.triggers = []
await self.save_triggers()
async def get_usernames(self, entity):
usernames = []
if entity.username:
username = entity.username
if username:
usernames.append(username.lower())
if entity.usernames:
additional_usernames = [
u.username.lower() for u in (getattr(entity, "usernames", []) or [])
]
usernames.extend(additional_usernames)
return usernames
async def list_triggerscmd(self, message):
"""показать все существующие триггеры"""
if not self.triggers:
await utils.answer(message, "🙂 Нет активных триггеров")
return
reply_with_html = "ℹ️ Список триггеров:\n\n"
reply_plain_text = "Список триггеров:\n\n"
for i, trigger in enumerate(self.triggers):
conditions = "\n".join([f"- {k}: {v}" for k, v in trigger["conditions"].items()])
if not conditions:
conditions = "Нет условий (all=true)"
reply_with_html += f"{i}. Условия:\n{conditions}\n\n💬 Ответ: {trigger['response']}\n\n"
reply_plain_text += f"{i}.\nУсловия:\n{conditions}\nОтвет: {trigger['response']}\n\n"
if len(reply_with_html) > 4096:
file_path = "triggers_list.txt"
with open(file_path, "w", encoding="utf-8") as file:
file.write(reply_plain_text)
await message.delete()
await self.client.send_file(message.chat, caption="📁 Вывод команды слишком длинный, поэтому он отправлен в файле.", file=file_path)
os.remove(file_path)
else:
await utils.answer(message, reply_with_html)
async def split(self, input_str):
is_in_quotes = False
split_index = -1
for i, char in enumerate(input_str):
if char == '"':
is_in_quotes = not is_in_quotes
elif char == '|' and not is_in_quotes:
split_index = i
break
if split_index == -1:
raise ValueError("Некорректный формат: отсутствует разделитель '|'")
return input_str[:split_index].strip(), input_str[split_index + 1:].strip()
async def add_triggercmd(self, message):
"""<условия> | <ответ> - добавить новый триггер"""
args = utils.get_args_raw(message)
if not args or "|" not in args:
await utils.answer(
message,
"🚫 Формат: <условия> | <ответ>\n✨ Пример: text=\"Привет\" | Здравствуй!"
)
return
try:
conditions_raw, response = await self.split(args)
valid_keys = {
"text", "user", "chat", "starts_with", "ends_with", "contains",
"regex", "is_command", "word_count", "char_count", "is_reply", "is_forwarded",
"media_type", "message_length", "time_range", "date", "weekday", "all"
}
conditions = {}
pattern = r'(\w+)=((?:\"(?:[^\"]|\\\")*\"|[^,\s]+))'
matches = re.finditer(pattern, conditions_raw)
for match in matches:
key, value = match.group(1), match.group(2)
if key not in valid_keys:
raise ValueError(f"Некорректное условие: {key}")
if key in {"text", "regex", "contains", "starts_with", "ends_with"}:
if not (value.startswith('"') and value.endswith('"')):
raise ValueError(f"Значение для условия {key} должно быть в кавычках")
value = value[1:-1].replace('\\"', '"')
if key == "all" and value.lower() == "true":
conditions = {"all": True}
break
conditions[key] = value
if not conditions:
raise ValueError(
"😨 Ты не указал никаких условий.. Если ты такой смелый, укажи all=true в условиях!"
)
if conditions.get("all"):
conditions = {}
await self.add_trigger(conditions, response)
conditions_str = "\n".join([f"- {k}: {v}" for k, v in conditions.items()])
if not conditions_str:
conditions_str = "Нет условий (all=true)"
await utils.answer(
message,
f"⚡️ Триггер добавлен!\n\nУсловия:\n{conditions_str}\n\n💬 Ответ: {response}"
)
except ValueError as e:
await utils.answer(message, f"🚫 Ошибка: {e}")
except Exception as e:
await utils.answer(message, f"🚫 Непредвиденная ошибка: {e}")
async def remove_triggercmd(self, message):
"""<номер> - удалить триггер"""
args = utils.get_args_raw(message)
if not args.isdigit():
await utils.answer(
message,
"🚫 Укажи номер триггера для удаления"
)
return
index = int(args)
if await self.remove_trigger(index):
await utils.answer(message, "🗑 Триггер удалён!")
else:
await utils.answer(message, "🚫 Неверный номер триггера")
async def clear_triggerscmd(self, message):
"""удалить все триггеры"""
await self.clear_triggers()
await utils.answer(message, "🗑 Все триггеры удалены!")
async def trigger(self, message):
if not self.config["watcher_on"]:
return
responses = []
for trigger in self.triggers:
conditions = trigger["conditions"]
match = True
for key, value in conditions.items():
value = value.strip('"')
if key == "text" and value.lower() != message.raw_text.lower():
match = False
break
elif key == "user" and not await self.validate(value, message.sender):
match = False
break
elif key == "chat" and not await self.validate(value, message.chat):
match = False
break
elif key == "starts_with" and not message.raw_text.lower().startswith(value.lower()):
match = False
break
elif key == "ends_with" and not message.raw_text.lower().endswith(value.lower()):
match = False
break
elif key == "contains" and value.lower() not in message.raw_text.lower():
match = False
break
elif key == "regex" and not re.search(value, message.raw_text):
match = False
break
elif key == "is_command" and value.lower() == "true" and not message.raw_text.startswith("/"):
match = False
break
elif key == "word_count" and len(message.raw_text.split()) != int(value):
match = False
break
elif key == "char_count" and len(message.raw_text) != int(value):
match = False
break
elif key == "is_reply" and value.lower() == "true" and not message.is_reply:
match = False
break
elif key == "is_forwarded" and value.lower() == "true" and not message.fwd_from:
match = False
break
elif key == "media_type":
media_types = {"photo": message.photo, "video": message.video, "sticker": message.sticker, "voice": message.voice, "audio": message.audio}
if not media_types.get(value.lower()):
match = False
break
elif key == "message_length" and not (int(value.split("-", 1)[0]) <= len(message.raw_text) <= int(value.split("-", 1)[1])):
match = False
break
elif key == "time_range" and not (int(value.split("-", 1)[0]) <= message.date.hour <= int(value.split("-", 1)[1])):
match = False
break
elif key == "date" and value != message.date.strftime("%Y-%m-%d"):
match = False
break
elif key == "weekday" and value.lower() != message.date.strftime("%A").lower():
match = False
break
if match:
responses.append(trigger["response"])
for response in responses:
await message.reply(response)