diff --git a/keyword/main.py b/keyword/main.py new file mode 100644 index 0000000..1bcb94a --- /dev/null +++ b/keyword/main.py @@ -0,0 +1,296 @@ +import contextlib + +from typing import Optional, List + +from datetime import datetime, timedelta + +from pyrogram.enums import ParseMode +from pyrogram.types import ChatPermissions, Chat +from pyrogram.types.user_and_chats.user import Link + +from pagermaid import bot +from pagermaid.listener import listener +from pagermaid.single_utils import sqlite, Message +from pagermaid.scheduler import add_delete_message_job + + +class KeywordTask: + task_id: Optional[int] + cid: int + key: str + msg: str + include: bool + exact: bool + case: bool + ignore_forward: bool + reply: bool + delete: bool + ban: int + restrict: int + delay_delete: int + + def __init__(self, task_id: Optional[int] = None, cid: int = 0, key: str = "", msg: str = "", include: bool = True, + exact: bool = False, case: bool = False, ignore_forward: bool = False, + reply: bool = True, delete: bool = False, ban: int = 0, restrict: int = 0, delay_delete: int = 0): + self.task_id = task_id + self.cid = cid + self.key = key + self.msg = msg + self.include = include + self.exact = exact + self.case = case + self.ignore_forward = ignore_forward + self.reply = reply + self.delete = delete + self.ban = ban + self.restrict = restrict + self.delay_delete = delay_delete + + def export(self): + return {"task_id": self.task_id, "cid": self.cid, "key": self.key, "msg": self.msg, "include": self.include, + "exact": self.exact, "case": self.case, "ignore_forward": self.ignore_forward, "reply": self.reply, + "delete": self.delete, "ban": self.ban, "restrict": self.restrict, "delay_delete": self.delay_delete} + + def export_str(self, show_all: bool = False): + text = f"{self.task_id} - " + text += f"{self.key} - " + if show_all: + text += f"{self.cid} - " + text += f"{self.msg}" + return text + + def save_to_file(self): + data = sqlite.get("keyword_tasks", []) + for i in data: + if i["task_id"] == self.task_id: + data.remove(i) + break + data.append(self.export()) + sqlite["keyword_tasks"] = data + + def check_need_reply(self, message: Message) -> bool: + if not (message.text or message.caption): + return False + if self.ignore_forward and message.forward_date: + return False + text = message.text or message.caption + key = self.key + if not self.case: + text = text.lower() + key = key.lower() + if self.include and text.find(key) != -1: + return True + if self.exact and text == key: + return True + return False + + @staticmethod + def mention_chat(chat: Chat): + return f'{chat.title}' if chat.username \ + else f'{chat.title}' + + def replace_reply(self, message: Message): + text = self.msg + if message.from_user: + text = text.replace("$mention", str(Link( + f"tg://user?id={message.from_user.id}", + message.from_user.first_name or "Deleted Account", + ParseMode.HTML + ))) + text = text.replace("$code_id", str(message.from_user.id)) + text = text.replace("$code_name", message.from_user.first_name or "Deleted Account") + elif message.sender_chat: + text = text.replace("$mention", self.mention_chat(message.sender_chat)) + text = text.replace("$code_id", str(message.sender_chat.id)) + text = text.replace("$code_name", message.sender_chat.title) + else: + text = text.replace("$mention", "") + text = text.replace("$code_id", "") + text = text.replace("$code_name", "") + if self.delay_delete: + text = text.replace("$delay_delete", str(self.delay_delete)) + else: + text = text.replace("$delay_delete", "") + return text + + async def process_keyword(self, message: Message): + msg = None + text = self.replace_reply(message) + with contextlib.suppress(Exception): + msg = await message.reply(text, quote=self.reply, parse_mode=ParseMode.HTML) + if self.delete: + await message.safe_delete() + uid = message.from_user.id if message.from_user else message.sender_chat.id + if self.ban > 0: + with contextlib.suppress(Exception): + await bot.ban_chat_member( + message.chat.id, uid, until_date=datetime.now() + timedelta(seconds=self.ban)) + if self.restrict > 0: + with contextlib.suppress(Exception): + await bot.restrict_chat_member( + message.chat.id, uid, ChatPermissions(), + until_date=datetime.now() + timedelta(seconds=self.restrict)) + if self.delay_delete > 0 and msg: + add_delete_message_job(msg, self.delay_delete) + + def parse_task(self, text: str): + data = text.split("\n+++\n") + if len(data) < 2: + raise ValueError("Invalid task format") + for i in data: + if i == "": + raise ValueError("Invalid task format") + + self.key = data[0] + self.msg = data[1] + + if len(data) > 2: + temp = data[2].split(" ") + for i in temp: + if i.startswith("include"): + self.include = True + elif i.startswith("exact"): + self.exact = True + elif i.startswith("case"): + self.case = True + elif i.startswith("ignore_forward"): + self.ignore_forward = True + else: + raise ValueError("Invalid task format") + if self.include and self.exact: + raise ValueError("Invalid task format") + + if len(data) > 3: + temp = data[3].split(" ") + for i in temp: + if i.startswith("reply"): + self.reply = True + elif i.startswith("delete"): + self.delete = True + elif i.startswith("ban"): + self.ban = int(i.replace("ban", "")) + elif i.startswith("restrict"): + self.restrict = int(i.replace("restrict", "")) + else: + raise ValueError("Invalid task format") + + if len(data) > 4: + self.delay_delete = int(data[4]) + + if self.ban < 0 or self.restrict < 0 or self.delay_delete < 0: + raise ValueError("Invalid task format") + + +class KeywordTasks: + tasks: List[KeywordTask] + + def __init__(self): + self.tasks = [] + + def add(self, task: KeywordTask): + for i in self.tasks: + if i.task_id == task.task_id: + return + self.tasks.append(task) + + def remove(self, task_id: int): + for task in self.tasks: + if task.task_id == task_id: + self.tasks.remove(task) + return True + return False + + def get(self, task_id: int) -> Optional[KeywordTask]: + return next((task for task in self.tasks if task.task_id == task_id), None) + + def get_all(self) -> List[KeywordTask]: + return self.tasks + + def get_all_ids(self) -> List[int]: + return [task.task_id for task in self.tasks] + + def print_all_tasks(self, show_all: bool = False, cid: int = 0) -> str: + return "\n".join(task.export_str(show_all) for task in self.tasks if task.cid == cid or show_all) + + def save_to_file(self): + data = [task.export() for task in self.tasks] + sqlite["keyword_tasks"] = data + + def load_from_file(self): + data = sqlite.get("keyword_tasks", []) + for i in data: + self.add(KeywordTask(**i)) + + def get_next_task_id(self): + return max(task.task_id for task in self.tasks) + 1 if self.tasks else 1 + + def get_tasks_for_chat(self, cid: int) -> List[KeywordTask]: + return [task for task in self.tasks if task.cid == cid] + + async def check_and_reply(self, message: Message): + for task in self.get_tasks_for_chat(message.chat.id): + if task.check_need_reply(message): + with contextlib.suppress(Exception): + await task.process_keyword(message) + + +keyword_tasks = KeywordTasks() +keyword_tasks.load_from_file() + + +async def from_msg_get_task_id(message: Message): + uid = -1 + try: + uid = int(message.parameter[1]) + except ValueError: + await message.edit("请输入正确的参数") + message.continue_propagation() + ids = keyword_tasks.get_all_ids() + if uid not in ids: + await message.edit("该任务不存在") + message.continue_propagation() + return uid + + +@listener(command="keyword", + parameters="指定参数", + description="关键词回复\n\nhttps://telegra.ph/PagerMaid-keyword-07-12") +async def keyword_set(message: Message): + if message.arguments == "h" or len(message.parameter) == 0: + return await message.edit("关键词回复\n\nhttps://telegra.ph/PagerMaid-keyword-07-12") + if len(message.parameter) == 1 and message.parameter[0] == "list": + if keyword_tasks.get_all_ids(): + return await message.edit( + f"关键词任务:\n\n{keyword_tasks.print_all_tasks(show_all=False, cid=message.chat.id)}") + else: + return await message.edit("没有关键词任务。") + if len(message.parameter) == 2: + if message.parameter[0] == "rm": + if uid := await from_msg_get_task_id(message): + keyword_tasks.remove(uid) + keyword_tasks.save_to_file() + keyword_tasks.load_from_file() + return await message.edit(f"已删除任务 {uid}") + elif message.parameter[0] == "list": + if keyword_tasks.get_all_ids(): + return await message.edit( + f"关键词任务:\n\n{keyword_tasks.print_all_tasks(show_all=True)}") + else: + return await message.edit("没有关键词任务。") + # add task + task = KeywordTask(keyword_tasks.get_next_task_id()) + task.cid = message.chat.id + try: + task.parse_task(message.arguments) + except Exception as e: + return await message.edit(f"参数错误:{e}") + keyword_tasks.add(task) + keyword_tasks.save_to_file() + keyword_tasks.load_from_file() + await message.edit(f"已添加关键词任务 {task.task_id}") + + +@listener(is_plugin=True, incoming=True, outgoing=False) +async def process_keyword(message): + with contextlib.suppress(Exception): + await keyword_tasks.check_and_reply(message) diff --git a/list.json b/list.json index d6b282b..dbd6071 100644 --- a/list.json +++ b/list.json @@ -309,6 +309,16 @@ "supported": true, "des-short": "导出、导入已加入的群组/频道(仅可导入公开群组/频道)", "des": "导出、导入已加入的群组/频道(仅可导入公开群组/频道)\n指令:,chat_transfer" + }, + { + "name": "keyword", + "version": "1.0", + "section": "chat", + "maintainer": "xtaodada", + "size": "10.9 kb", + "supported": true, + "des-short": "关键词回复。", + "des": "关键词回复。\n指令:,keyword" } ] }