diff --git a/pagermaid/__init__.py b/pagermaid/__init__.py index 80f71ff..f2bcbab 100644 --- a/pagermaid/__init__.py +++ b/pagermaid/__init__.py @@ -4,7 +4,16 @@ from typing import Callable, Awaitable, Set, Dict from coloredlogs import ColoredFormatter from datetime import datetime, timezone -from logging import getLogger, StreamHandler, CRITICAL, INFO, basicConfig, DEBUG, Formatter, FileHandler +from logging import ( + getLogger, + StreamHandler, + CRITICAL, + INFO, + basicConfig, + DEBUG, + Formatter, + FileHandler, +) from os import getcwd from pagermaid.config import Config @@ -12,8 +21,8 @@ from pagermaid.scheduler import scheduler import pyromod.listen from pyrogram import Client -pgm_version = "1.3.0" -pgm_version_code = 1300 +pgm_version = "1.3.1" +pgm_version_code = 1301 CMD_LIST = {} module_dir = __path__[0] working_dir = getcwd() @@ -21,7 +30,11 @@ working_dir = getcwd() read_context = {} help_messages = {} hook_functions: Dict[str, Set[Callable[[], Awaitable[None]]]] = { - "startup": set(), "shutdown": set(), "command_pre": set(), "command_post": set(), "process_error": set(), + "startup": set(), + "shutdown": set(), + "command_pre": set(), + "command_post": set(), + "process_error": set(), "load_plugins_finished": set(), } all_permissions = [] @@ -51,6 +64,7 @@ start_time = datetime.now(timezone.utc) with contextlib.suppress(ImportError): import uvloop # noqa + uvloop.install() if not scheduler.running: @@ -68,16 +82,11 @@ bot.job = scheduler async def log(message): - logs.info( - message.replace('`', '\"') - ) + logs.info(message.replace("`", '"')) if not Config.LOG: return try: - await bot.send_message( - Config.LOG_ID, - message - ) + await bot.send_message(Config.LOG_ID, message) except Exception: Config.LOG = False Config.LOG_ID = "me" diff --git a/pagermaid/__main__.py b/pagermaid/__main__.py index a29bf99..a8ea56b 100644 --- a/pagermaid/__main__.py +++ b/pagermaid/__main__.py @@ -17,7 +17,7 @@ path.insert(1, f"{working_dir}{sep}plugins") async def main(): - logs.info(lang('platform') + platform + lang('platform_load')) + logs.info(lang("platform") + platform + lang("platform_load")) try: await start_client(bot) @@ -35,7 +35,9 @@ async def main(): try: import_module(f"pagermaid.modules.{module_name}") except BaseException as exception: - logs.info(f"{lang('module')} {module_name} {lang('error')}: {type(exception)}: {exception}") + logs.info( + f"{lang('module')} {module_name} {lang('error')}: {type(exception)}: {exception}" + ) for plugin_name in plugin_list.copy(): try: import_module(f"plugins.{plugin_name}") @@ -45,11 +47,12 @@ async def main(): plugin_manager.load_local_plugins() await process_exit(start=True, _client=bot) - logs.info(lang('start')) + logs.info(lang("start")) await Hook.load_success_exec() await Hook.startup() await idle() await bot.stop() + bot.run(main()) diff --git a/pagermaid/common/alias.py b/pagermaid/common/alias.py index 5daa8ef..894c361 100644 --- a/pagermaid/common/alias.py +++ b/pagermaid/common/alias.py @@ -28,15 +28,12 @@ class AliasManager: def get_all_alias_text(self) -> str: texts = [] - texts.extend( - f'`{i.command}` > `{i.alias}`' - for i in self.alias_list - ) - return '\n'.join(texts) + texts.extend(f"`{i.command}` > `{i.alias}`" for i in self.alias_list) + return "\n".join(texts) @staticmethod def save(): - with open(f"data{sep}alias.json", 'w', encoding="utf-8") as f: + with open(f"data{sep}alias.json", "w", encoding="utf-8") as f: json_dump(Config.alias_dict, f) @staticmethod diff --git a/pagermaid/common/cache.py b/pagermaid/common/cache.py index ccada32..6ddb329 100644 --- a/pagermaid/common/cache.py +++ b/pagermaid/common/cache.py @@ -20,7 +20,7 @@ def cache(ttl=datetime.timedelta(minutes=15)): nonlocal cache_data bound = inspect.signature(func).bind(*args, **kw) bound.apply_defaults() - ins_key = '|'.join([f'{k}_{v}' for k, v in bound.arguments.items()]) + ins_key = "|".join([f"{k}_{v}" for k, v in bound.arguments.items()]) data: Cache = cache_data.get(ins_key, Cache(value=None, time=None)) now = datetime.datetime.now() if (not data.time) or ((now - data.time) > ttl): @@ -31,5 +31,7 @@ def cache(ttl=datetime.timedelta(minutes=15)): except Exception as e: raise e return data.value + return wrapped + return wrap diff --git a/pagermaid/common/plugin.py b/pagermaid/common/plugin.py index 3a0cfef..9cb600e 100644 --- a/pagermaid/common/plugin.py +++ b/pagermaid/common/plugin.py @@ -10,7 +10,7 @@ from pagermaid import Config from pagermaid.common.cache import cache from pagermaid.utils import client -plugins_path = Path('plugins') +plugins_path = Path("plugins") class LocalPlugin(BaseModel): @@ -57,11 +57,11 @@ class RemotePlugin(LocalPlugin): ... async def install(self) -> bool: - html = await client.get(f'{Config.GIT_SOURCE}{self.name}/main.py') + html = await client.get(f"{Config.GIT_SOURCE}{self.name}/main.py") if html.status_code == 200: self.remove() with open(plugins_path / f"{self.name}.py", mode="wb") as f: - f.write(html.text.encode('utf-8')) + f.write(html.text.encode("utf-8")) return True return False @@ -76,11 +76,11 @@ class PluginManager: def load_local_version_map(self): if not os.path.exists(plugins_path / "version.json"): return - with open(plugins_path / "version.json", 'r', encoding="utf-8") as f: + with open(plugins_path / "version.json", "r", encoding="utf-8") as f: self.version_map = json.load(f) def save_local_version_map(self): - with open(plugins_path / "version.json", 'w', encoding="utf-8") as f: + with open(plugins_path / "version.json", "w", encoding="utf-8") as f: json.dump(self.version_map, f, indent=4) def get_local_version(self, name: str) -> Optional[float]: @@ -116,15 +116,17 @@ class PluginManager: def load_local_plugins(self) -> List[LocalPlugin]: self.load_local_version_map() self.plugins = [] - for plugin in os.listdir('plugins'): - if plugin.endswith('.py') or plugin.endswith('.py.disabled'): - plugin = plugin[:-12] if plugin.endswith('.py.disabled') else plugin[:-3] + for plugin in os.listdir("plugins"): + if plugin.endswith(".py") or plugin.endswith(".py.disabled"): + plugin = ( + plugin[:-12] if plugin.endswith(".py.disabled") else plugin[:-3] + ) self.plugins.append( LocalPlugin( name=plugin, installed=self.get_plugin_install_status(plugin), status=self.get_plugin_load_status(plugin), - version=self.get_local_version(plugin) + version=self.get_local_version(plugin), ) ) return self.plugins @@ -140,7 +142,8 @@ class PluginManager: RemotePlugin( **plugin, status=False, - ) for plugin in plugin_list + ) + for plugin in plugin_list ] self.remote_plugins = plugins self.remote_version_map = {} diff --git a/pagermaid/common/reload.py b/pagermaid/common/reload.py index 6917d04..92fdb1a 100644 --- a/pagermaid/common/reload.py +++ b/pagermaid/common/reload.py @@ -4,7 +4,14 @@ import os import pagermaid.config import pagermaid.modules -from pagermaid import read_context, bot, help_messages, all_permissions, hook_functions, logs +from pagermaid import ( + read_context, + bot, + help_messages, + all_permissions, + hook_functions, + logs, +) from pagermaid.common.plugin import plugin_manager from pagermaid.hook import Hook from pagermaid.utils import lang @@ -32,7 +39,9 @@ async def reload_all(): if module_name in loaded_plugins: importlib.reload(module) except BaseException as exception: - logs.info(f"{lang('module')} {module_name} {lang('error')}: {type(exception)}: {exception}") + logs.info( + f"{lang('module')} {module_name} {lang('error')}: {type(exception)}: {exception}" + ) for plugin_name in pagermaid.modules.plugin_list.copy(): try: plugin = importlib.import_module(f"plugins.{plugin_name}") diff --git a/pagermaid/common/status.py b/pagermaid/common/status.py index 3ff91e5..e2d0ba2 100644 --- a/pagermaid/common/status.py +++ b/pagermaid/common/status.py @@ -17,11 +17,11 @@ class Status(BaseModel): async def human_time_duration(seconds) -> str: parts = {} time_units = ( - ('%m', 60 * 60 * 24 * 30), - ('%d', 60 * 60 * 24), - ('%H', 60 * 60), - ('%M', 60), - ('%S', 1) + ("%m", 60 * 60 * 24 * 30), + ("%d", 60 * 60 * 24), + ("%H", 60 * 60), + ("%M", 60), + ("%S", 1), ) for unit, div in time_units: amount, seconds = divmod(int(seconds), div) @@ -48,7 +48,7 @@ async def get_status() -> Status: return Status( version=pgm_version, run_time=uptime, - cpu_percent=f'{cpu_percent}%', - ram_percent=f'{ram_stat.percent}%', - swap_percent=f'{swap_stat.percent}%', + cpu_percent=f"{cpu_percent}%", + ram_percent=f"{ram_stat.percent}%", + swap_percent=f"{swap_stat.percent}%", ) diff --git a/pagermaid/common/system.py b/pagermaid/common/system.py index dee7b21..bda9fed 100644 --- a/pagermaid/common/system.py +++ b/pagermaid/common/system.py @@ -33,11 +33,11 @@ async def run_eval(cmd: str, message=None, only_result: bool = False) -> str: async def aexec(code, event, client): exec( ( - ( - ("async def __aexec(e, client): " + "\n msg = message = e") - + "\n reply = message.reply_to_message if message else None" - ) - + "\n chat = e.chat if e else None" + ( + ("async def __aexec(e, client): " + "\n msg = message = e") + + "\n reply = message.reply_to_message if message else None" + ) + + "\n chat = e.chat if e else None" ) + "".join(f"\n {x}" for x in code.split("\n")) ) diff --git a/pagermaid/common/update.py b/pagermaid/common/update.py index 7441472..c548adf 100644 --- a/pagermaid/common/update.py +++ b/pagermaid/common/update.py @@ -4,9 +4,9 @@ from pagermaid.utils import execute async def update(force: bool = False): - await execute('git fetch --all') + await execute("git fetch --all") if force: - await execute('git reset --hard origin/master') - await execute('git pull --all') + await execute("git reset --hard origin/master") + await execute("git pull --all") await execute(f"{executable} -m pip install --upgrade -r requirements.txt") await execute(f"{executable} -m pip install -r requirements.txt") diff --git a/pagermaid/config.py b/pagermaid/config.py index ee670eb..1e21f19 100644 --- a/pagermaid/config.py +++ b/pagermaid/config.py @@ -15,9 +15,9 @@ def strtobool(val, default=False): 'val' is anything else. """ val = val.lower() - if val in ('y', 'yes', 't', 'true', 'on', '1'): + if val in ("y", "yes", "t", "true", "on", "1"): return 1 - elif val in ('n', 'no', 'f', 'false', 'off', '0'): + elif val in ("n", "no", "f", "false", "off", "0"): return 0 else: print("[Degrade] invalid truth value %r" % (val,)) @@ -27,7 +27,9 @@ def strtobool(val, default=False): try: config: Dict = load(open(r"config.yml", encoding="utf-8"), Loader=FullLoader) except FileNotFoundError: - print("The configuration file does not exist, and a new configuration file is being generated.") + print( + "The configuration file does not exist, and a new configuration file is being generated." + ) copyfile(f"{os.getcwd()}{os.sep}config.gen.yml", "config.yml") sys.exit(1) @@ -43,19 +45,29 @@ class Config: # TGX API_ID = DEFAULT_API_ID API_HASH = DEFAULT_API_HASH - QRCODE_LOGIN = strtobool(os.environ.get("QRCODE_LOGIN", config.get("qrcode_login", "false"))) + QRCODE_LOGIN = strtobool( + os.environ.get("QRCODE_LOGIN", config.get("qrcode_login", "false")) + ) STRING_SESSION = os.environ.get("STRING_SESSION") DEBUG = strtobool(os.environ.get("PGM_DEBUG", config["debug"])) - ERROR_REPORT = strtobool(os.environ.get("PGM_ERROR_REPORT", config["error_report"]), True) + ERROR_REPORT = strtobool( + os.environ.get("PGM_ERROR_REPORT", config["error_report"]), True + ) LANGUAGE = os.environ.get("PGM_LANGUAGE", config["application_language"]) REGION = os.environ.get("PGM_REGION", config["application_region"]) - TIME_ZONE = os.environ.get("PGM_TIME_ZONE", config.get("timezone", "Asia/Shanghai")) + TIME_ZONE = os.environ.get( + "PGM_TIME_ZONE", config.get("timezone", "Asia/Shanghai") + ) TTS = os.environ.get("PGM_TTS", config["application_tts"]) LOG = strtobool(os.environ.get("PGM_LOG", config["log"])) LOG_ID = int(os.environ.get("PGM_LOG_ID", config["log_chatid"])) IPV6 = strtobool(os.environ.get("PGM_IPV6", config["ipv6"])) - ALLOW_ANALYTIC = strtobool(os.environ.get("PGM_ALLOW_ANALYTIC", config["allow_analytic"]), True) - SENTRY_API = "https://2e13a517aeb542e7a307cba8996b6d1a@o1342815.ingest.sentry.io/6617119" + ALLOW_ANALYTIC = strtobool( + os.environ.get("PGM_ALLOW_ANALYTIC", config["allow_analytic"]), True + ) + SENTRY_API = ( + "https://2e13a517aeb542e7a307cba8996b6d1a@o1342815.ingest.sentry.io/6617119" + ) MIXPANEL_API = "c79162511383b0fa1e9c062a2a86c855" TIME_FORM = os.environ.get("PGM_TIME_FORM", config["time_form"]) DATE_FORM = os.environ.get("PGM_DATE_FORM", config["date_form"]) @@ -63,31 +75,39 @@ class Config: SILENT = strtobool(os.environ.get("PGM_PGM_SILENT", config["silent"]), True) PROXY_ADDRESS = os.environ.get("PGM_PROXY_ADDRESS", config["proxy_addr"]) PROXY_PORT = os.environ.get("PGM_PROXY_PORT", config["proxy_port"]) - PROXY_HTTP_ADDRESS = os.environ.get("PGM_PROXY_HTTP_ADDRESS", config["http_addr"]) + PROXY_HTTP_ADDRESS = os.environ.get( + "PGM_PROXY_HTTP_ADDRESS", config["http_addr"] + ) PROXY_HTTP_PORT = os.environ.get("PGM_PROXY_HTTP_PORT", config["http_port"]) PROXY = None if PROXY_ADDRESS and PROXY_PORT: - PROXY = dict( - scheme="socks5", - hostname=PROXY_ADDRESS, - port=int(PROXY_PORT) - ) + PROXY = dict(scheme="socks5", hostname=PROXY_ADDRESS, port=int(PROXY_PORT)) elif PROXY_HTTP_ADDRESS and PROXY_HTTP_PORT: PROXY = dict( - scheme="http", - hostname=PROXY_HTTP_ADDRESS, - port=int(PROXY_HTTP_PORT) + scheme="http", hostname=PROXY_HTTP_ADDRESS, port=int(PROXY_HTTP_PORT) ) GIT_SOURCE = os.environ.get("PGM_GIT_SOURCE", config["git_source"]) - GIT_SOURCE = GIT_SOURCE.replace("TeamPGM/PagerMaid_Plugins/", "TeamPGM/PagerMaid_Plugins_Pyro/") + GIT_SOURCE = GIT_SOURCE.replace( + "TeamPGM/PagerMaid_Plugins/", "TeamPGM/PagerMaid_Plugins_Pyro/" + ) try: - with open(f"languages{os.sep}built-in{os.sep}{LANGUAGE}.yml", "r", encoding="utf-8") as f: + with open( + f"languages{os.sep}built-in{os.sep}{LANGUAGE}.yml", + "r", + encoding="utf-8", + ) as f: lang_dict = safe_load(f) except Exception as e: - print("[Degrade] Reading language YAML file failed, try to use the english language file.") + print( + "[Degrade] Reading language YAML file failed, try to use the english language file." + ) print(e) try: - with open(f"languages{os.sep}built-in{os.sep}{LANGUAGE}.yml", "r", encoding="utf-8") as f: + with open( + f"languages{os.sep}built-in{os.sep}{LANGUAGE}.yml", + "r", + encoding="utf-8", + ) as f: lang_dict = safe_load(f) except Exception as e: print("[Error] Reading English language YAML file failed.") @@ -99,8 +119,12 @@ class Config: except Exception as e: alias_dict = {} web_interface = config.get("web_interface", {}) - WEB_ENABLE = strtobool(os.environ.get("WEB_ENABLE", web_interface.get("enable", "False"))) - WEB_SECRET_KEY = os.environ.get("WEB_SECRET_KEY", web_interface.get("secret_key", "secret_key")) + WEB_ENABLE = strtobool( + os.environ.get("WEB_ENABLE", web_interface.get("enable", "False")) + ) + WEB_SECRET_KEY = os.environ.get( + "WEB_SECRET_KEY", web_interface.get("secret_key", "secret_key") + ) WEB_HOST = os.environ.get("WEB_HOST", web_interface.get("host", "127.0.0.1")) WEB_PORT = int(os.environ.get("WEB_PORT", web_interface.get("port", 3333))) WEB_ORIGINS = web_interface.get("origins", ["*"]) diff --git a/pagermaid/group_manager.py b/pagermaid/group_manager.py index 815e2a5..40db120 100644 --- a/pagermaid/group_manager.py +++ b/pagermaid/group_manager.py @@ -9,8 +9,13 @@ from pagermaid import all_permissions, module_dir # init permissions if not os_path.exists(f"data{os_path.sep}gm_policy.csv"): - copyfile(f"{module_dir}{os_path.sep}assets{os_path.sep}gm_policy.csv", f"data{os_path.sep}gm_policy.csv") -permissions = casbin.Enforcer(f"pagermaid{sep}assets{sep}gm_model.conf", f"data{sep}gm_policy.csv") + copyfile( + f"{module_dir}{os_path.sep}assets{os_path.sep}gm_policy.csv", + f"data{os_path.sep}gm_policy.csv", + ) +permissions = casbin.Enforcer( + f"pagermaid{sep}assets{sep}gm_model.conf", f"data{sep}gm_policy.csv" +) permissions.logger.setLevel(CRITICAL) @@ -27,15 +32,14 @@ def enforce_permission(user: int, permission: str): data = permission.split(".") if len(data) != 2: raise ValueError("Invalid permission format") - if permissions.enforce( - str(user), data[0], "access" - ) and not permissions.enforce(str(user), permission, "ejection"): + if permissions.enforce(str(user), data[0], "access") and not permissions.enforce( + str(user), permission, "ejection" + ): return True - if permissions.enforce( - str(user), permission, "access" - ) and not permissions.enforce(str(user), permission, "ejection"): - return True - return False + return bool( + permissions.enforce(str(user), permission, "access") + and not permissions.enforce(str(user), permission, "ejection") + ) def parse_pen(pen: Permission) -> List[Permission]: @@ -45,7 +49,11 @@ def parse_pen(pen: Permission) -> List[Permission]: raise ValueError("Wildcard not allowed in root name") datas = [] for i in all_permissions: - if pen.root == i.root and len(findall(pen.sub.replace("*", r"([\s\S]*)"), i.sub)) > 0 and i not in datas: + if ( + pen.root == i.root + and len(findall(pen.sub.replace("*", r"([\s\S]*)"), i.sub)) > 0 + and i not in datas + ): datas.append(i) if not datas: raise ValueError("No permission found") diff --git a/pagermaid/hook.py b/pagermaid/hook.py index 85aa595..3189ce5 100644 --- a/pagermaid/hook.py +++ b/pagermaid/hook.py @@ -14,9 +14,11 @@ class Hook: """ 注册一个启动钩子 """ + def decorator(function): hook_functions["startup"].add(function) return function + return decorator @staticmethod @@ -24,9 +26,11 @@ class Hook: """ 注册一个关闭钩子 """ + def decorator(function): hook_functions["shutdown"].add(function) return function + return decorator @staticmethod @@ -79,7 +83,9 @@ class Hook: @staticmethod async def startup(): - if cors := [startup(**inject(None, startup)) for startup in hook_functions["startup"]]: # noqa + if cors := [ + startup(**inject(None, startup)) for startup in hook_functions["startup"] + ]: # noqa try: await asyncio.gather(*cors) except Exception as exception: @@ -87,7 +93,10 @@ class Hook: @staticmethod async def shutdown(): - if cors := [shutdown(**inject(None, shutdown)) for shutdown in hook_functions["shutdown"]]: # noqa + if cors := [ + shutdown(**inject(None, shutdown)) + for shutdown in hook_functions["shutdown"] + ]: # noqa try: await asyncio.gather(*cors) except Exception as exception: @@ -136,12 +145,20 @@ class Hook: logs.info(f"[command_post]: {type(exception)}: {exception}") @staticmethod - async def process_error_exec(message: Message, command, exc_info: BaseException, exc_format: str): + async def process_error_exec( + message: Message, command, exc_info: BaseException, exc_format: str + ): cors = [] try: for error in hook_functions["process_error"]: try: - data = inject(message, error, command=command, exc_info=exc_info, exc_format=exc_format) + data = inject( + message, + error, + command=command, + exc_info=exc_info, + exc_format=exc_format, + ) except Exception as exception: logs.info(f"[process_error]: {type(exception)}: {exception}") continue @@ -158,7 +175,10 @@ class Hook: @staticmethod async def load_success_exec(): - if cors := [load(**inject(None, load)) for load in hook_functions["load_plugins_finished"]]: # noqa + if cors := [ + load(**inject(None, load)) + for load in hook_functions["load_plugins_finished"] + ]: # noqa try: await asyncio.gather(*cors) except Exception as exception: diff --git a/pagermaid/listener.py b/pagermaid/listener.py index e988054..765bb59 100644 --- a/pagermaid/listener.py +++ b/pagermaid/listener.py @@ -10,7 +10,8 @@ from pyrogram.errors.exceptions.bad_request_400 import ( MessageIdInvalid, MessageNotModified, MessageEmpty, - UserNotParticipant, PeerIdInvalid + UserNotParticipant, + PeerIdInvalid, ) from pyrogram.handlers import MessageHandler, EditedMessageHandler @@ -18,15 +19,27 @@ from pagermaid import help_messages, logs, Config, bot, read_context, all_permis from pagermaid.common.ignore import ignore_groups_manager from pagermaid.group_manager import Permission from pagermaid.inject import inject -from pagermaid.single_utils import Message, AlreadyInConversationError, TimeoutConversationError, ListenerCanceled -from pagermaid.utils import lang, attach_report, sudo_filter, alias_command, get_permission_name, process_exit +from pagermaid.single_utils import ( + Message, + AlreadyInConversationError, + TimeoutConversationError, + ListenerCanceled, +) +from pagermaid.utils import ( + lang, + attach_report, + sudo_filter, + alias_command, + get_permission_name, + process_exit, +) from pagermaid.hook import Hook _lock = asyncio.Lock() def listener(**args): - """ Register an event listener. """ + """Register an event listener.""" command = args.get("command") disallow_alias = args.get("disallow_alias", False) need_admin = args.get("need_admin", False) @@ -46,7 +59,7 @@ def listener(**args): if priority < 0 or priority > 100: raise ValueError("Priority must be between 0 and 100.") elif priority == 0 and is_plugin: - """ Priority 0 is reserved for modules. """ + """Priority 0 is reserved for modules.""" priority = 1 elif (not is_plugin) and need_admin: priority = 0 @@ -54,11 +67,13 @@ def listener(**args): if command is not None: if command in help_messages: if help_messages[alias_command(command)]["priority"] <= priority: - raise ValueError(f"{lang('error_prefix')} {lang('command')} \"{command}\" {lang('has_reg')}") + raise ValueError( + f"{lang('error_prefix')} {lang('command')} \"{command}\" {lang('has_reg')}" + ) else: block_process = True - pattern = fr"^(,|,){alias_command(command, disallow_alias)}(?: |$)([\s\S]*)" - sudo_pattern = fr"^(/){alias_command(command, disallow_alias)}(?: |$)([\s\S]*)" + pattern = rf"^(,|,){alias_command(command, disallow_alias)}(?: |$)([\s\S]*)" + sudo_pattern = rf"^(/){alias_command(command, disallow_alias)}(?: |$)([\s\S]*)" if pattern is not None and not pattern.startswith("(?i)"): args["pattern"] = f"(?i){pattern}" else: @@ -72,11 +87,7 @@ def listener(**args): else: base_filters = filters.all permission_name = get_permission_name(is_plugin, need_admin, command) - sudo_filters = ( - sudo_filter(permission_name) - & ~filters.via_bot - & ~filters.forwarded - ) + sudo_filters = sudo_filter(permission_name) & ~filters.via_bot & ~filters.forwarded if args["pattern"]: base_filters &= filters.regex(args["pattern"]) sudo_filters &= filters.regex(sudo_pattern) @@ -112,7 +123,6 @@ def listener(**args): del args["block_process"] def decorator(function): - async def handler(client: Client, message: Message): try: # ignore @@ -155,30 +165,29 @@ def listener(**args): raise StopPropagation from e except KeyboardInterrupt as e: raise KeyboardInterrupt from e - except (UserNotParticipant, MessageNotModified, MessageEmpty, Flood, Forbidden, PeerIdInvalid): + except ( + UserNotParticipant, + MessageNotModified, + MessageEmpty, + Flood, + Forbidden, + PeerIdInvalid, + ): logs.warning( "An unknown chat error occurred while processing a command.", ) except MessageIdInvalid: - logs.warning( - "Please Don't Delete Commands While it's Processing.." - ) + logs.warning("Please Don't Delete Commands While it's Processing..") except AlreadyInConversationError: - logs.warning( - "Please Don't Send Commands In The Same Conversation.." - ) + logs.warning("Please Don't Send Commands In The Same Conversation..") with contextlib.suppress(BaseException): await message.edit(lang("conversation_already_in_error")) except TimeoutConversationError: - logs.warning( - "Conversation Timed out while processing commands.." - ) + logs.warning("Conversation Timed out while processing commands..") with contextlib.suppress(BaseException): await message.edit(lang("conversation_timed_out_error")) except ListenerCanceled: - logs.warning( - "Listener Canceled While Processing Commands.." - ) + logs.warning("Listener Canceled While Processing Commands..") with contextlib.suppress(BaseException): await message.edit(lang("reload_des")) except ContinuePropagation as e: @@ -199,35 +208,54 @@ def listener(**args): if Config.ERROR_REPORT: report = f"""# Generated: {strftime('%H:%M %d/%m/%Y', gmtime())}. \n# ChatID: {message.chat.id}. \n# UserID: {message.from_user.id if message.from_user else message.sender_chat.id}. \n# Message: \n-----BEGIN TARGET MESSAGE-----\n{message.text or message.caption}\n-----END TARGET MESSAGE-----\n# Traceback: \n-----BEGIN TRACEBACK-----\n{str(exc_format)}\n-----END TRACEBACK-----\n# Error: "{str(exc_info)}". \n""" - await attach_report(report, f"exception.{time()}.pgp.txt", None, - "PGP Error report generated.") - await Hook.process_error_exec(message, command, exc_info, exc_format) + await attach_report( + report, + f"exception.{time()}.pgp.txt", + None, + "PGP Error report generated.", + ) + await Hook.process_error_exec( + message, command, exc_info, exc_format + ) if (message.chat.id, message.id) in read_context: del read_context[(message.chat.id, message.id)] if block_process: message.stop_propagation() message.continue_propagation() - bot.add_handler(MessageHandler(handler, filters=base_filters), group=0 + priority) + bot.add_handler( + MessageHandler(handler, filters=base_filters), group=0 + priority + ) if command: - bot.add_handler(MessageHandler(handler, filters=sudo_filters), group=50 + priority) + bot.add_handler( + MessageHandler(handler, filters=sudo_filters), group=50 + priority + ) if not ignore_edited: - bot.add_handler(EditedMessageHandler(handler, filters=base_filters), group=1 + priority) + bot.add_handler( + EditedMessageHandler(handler, filters=base_filters), group=1 + priority + ) if command: - bot.add_handler(EditedMessageHandler(handler, filters=sudo_filters), group=51 + priority) + bot.add_handler( + EditedMessageHandler(handler, filters=sudo_filters), + group=51 + priority, + ) return handler if description is not None and command is not None: if parameters is None: parameters = "" - help_messages.update({ - f"{alias_command(command)}": {"permission": permission_name, - "use": f"**{lang('use_method')}:** `,{command} {parameters}`\n" - f"**{lang('need_permission')}:** `{permission_name}`\n" - f"{description}", - "priority": priority, } - }) + help_messages.update( + { + f"{alias_command(command)}": { + "permission": permission_name, + "use": f"**{lang('use_method')}:** `,{command} {parameters}`\n" + f"**{lang('need_permission')}:** `{permission_name}`\n" + f"{description}", + "priority": priority, + } + } + ) all_permissions.append(Permission(permission_name)) return decorator @@ -261,49 +289,53 @@ def raw_listener(filter_s): except ContinuePropagation as e: raise ContinuePropagation from e except MessageIdInvalid: - logs.warning( - "Please Don't Delete Commands While it's Processing.." - ) + logs.warning("Please Don't Delete Commands While it's Processing..") except AlreadyInConversationError: - logs.warning( - "Please Don't Send Commands In The Same Conversation.." - ) + logs.warning("Please Don't Send Commands In The Same Conversation..") with contextlib.suppress(BaseException): await message.edit(lang("conversation_already_in_error")) except TimeoutConversationError: - logs.warning( - "Conversation Timed out while processing commands.." - ) + logs.warning("Conversation Timed out while processing commands..") with contextlib.suppress(BaseException): await message.edit(lang("conversation_timed_out_error")) except ListenerCanceled: - logs.warning( - "Listener Canceled While Processing Commands.." - ) + logs.warning("Listener Canceled While Processing Commands..") with contextlib.suppress(BaseException): await message.edit(lang("reload_des")) except SystemExit: await process_exit(start=False, _client=client, message=message) await Hook.shutdown() sys.exit(0) - except (UserNotParticipant, MessageNotModified, MessageEmpty, Flood, Forbidden): + except ( + UserNotParticipant, + MessageNotModified, + MessageEmpty, + Flood, + Forbidden, + ): pass except BaseException: exc_info = sys.exc_info()[1] exc_format = format_exc() with contextlib.suppress(BaseException): - await message.edit(lang('run_error'), no_reply=True) + await message.edit(lang("run_error"), no_reply=True) if Config.ERROR_REPORT: - report = f"# Generated: {strftime('%H:%M %d/%m/%Y', gmtime())}. \n" \ - f"# ChatID: {message.chat.id}. \n" \ - f"# UserID: {message.from_user.id if message.from_user else message.sender_chat.id}. \n" \ - f"# Message: \n-----BEGIN TARGET MESSAGE-----\n" \ - f"{message.text}\n-----END TARGET MESSAGE-----\n" \ - f"# Traceback: \n-----BEGIN TRACEBACK-----\n" \ - f"{str(exc_format)}\n-----END TRACEBACK-----\n" \ - f"# Error: \"{str(exc_info)}\". \n" - await attach_report(report, f"exception.{time()}.pagermaid", None, - "Error report generated.") + report = ( + f"# Generated: {strftime('%H:%M %d/%m/%Y', gmtime())}. \n" + f"# ChatID: {message.chat.id}. \n" + f"# UserID: {message.from_user.id if message.from_user else message.sender_chat.id}. \n" + f"# Message: \n-----BEGIN TARGET MESSAGE-----\n" + f"{message.text}\n-----END TARGET MESSAGE-----\n" + f"# Traceback: \n-----BEGIN TRACEBACK-----\n" + f"{str(exc_format)}\n-----END TRACEBACK-----\n" + f'# Error: "{str(exc_info)}". \n' + ) + await attach_report( + report, + f"exception.{time()}.pagermaid", + None, + "Error report generated.", + ) message.continue_propagation() bot.add_handler(MessageHandler(handler, filters=filter_s), group=2) diff --git a/pagermaid/modules/__init__.py b/pagermaid/modules/__init__.py index 080d0a5..a1ee528 100644 --- a/pagermaid/modules/__init__.py +++ b/pagermaid/modules/__init__.py @@ -12,9 +12,7 @@ def __list_modules(): return [ basename(file)[:-3] for file in module_paths - if isfile(file) - and file.endswith(".py") - and not file.endswith("__init__.py") + if isfile(file) and file.endswith(".py") and not file.endswith("__init__.py") ] @@ -25,21 +23,15 @@ def __list_plugins(): return [ basename(file)[:-3] for file in plugin_paths - if isfile(file) - and file.endswith(".py") - and not file.endswith("__init__.py") + if isfile(file) and file.endswith(".py") and not file.endswith("__init__.py") ] -module_list_string = "".join( - f"{module}, " for module in sorted(__list_modules()) -) +module_list_string = "".join(f"{module}, " for module in sorted(__list_modules())) module_list_string = module_list_string[:-2] -plugin_list_string = "".join( - f"{plugin}, " for plugin in sorted(__list_plugins()) -) +plugin_list_string = "".join(f"{plugin}, " for plugin in sorted(__list_plugins())) plugin_list_string = plugin_list_string[:-2] diff --git a/pagermaid/modules/account.py b/pagermaid/modules/account.py index cf495eb..02ca108 100644 --- a/pagermaid/modules/account.py +++ b/pagermaid/modules/account.py @@ -11,16 +11,19 @@ from pagermaid.utils import lang import contextlib -@listener(is_plugin=False, command="profile", - description=lang('profile_des'), - parameters="") +@listener( + is_plugin=False, + command="profile", + description=lang("profile_des"), + parameters="", +) async def profile(client: Client, message: Message): - """ Queries profile of a user. """ + """Queries profile of a user.""" if len(message.parameter) > 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return if not Config.SILENT: - message = await message.edit(lang('profile_process')) + message = await message.edit(lang("profile_process")) if message.reply_to_message: user = message.reply_to_message.from_user if not user: @@ -43,39 +46,54 @@ async def profile(client: Client, message: Message): try: user = await client.get_users(user) except PeerIdInvalid: - return await message.edit(f"{lang('error_prefix')}{lang('profile_e_nof')}") + return await message.edit( + f"{lang('error_prefix')}{lang('profile_e_nof')}" + ) except UsernameNotOccupied: - return await message.edit(f"{lang('error_prefix')}{lang('profile_e_nou')}") + return await message.edit( + f"{lang('error_prefix')}{lang('profile_e_nou')}" + ) except OverflowError: - return await message.edit(f"{lang('error_prefix')}{lang('profile_e_long')}") + return await message.edit( + f"{lang('error_prefix')}{lang('profile_e_long')}" + ) except Exception as exception: raise exception - user_type = "Bot" if user.is_bot else lang('profile_user') - username_system = f"@{user.username}" if user.username is not None else lang('profile_noset') + user_type = "Bot" if user.is_bot else lang("profile_user") + username_system = ( + f"@{user.username}" if user.username is not None else lang("profile_noset") + ) if not user.first_name: await message.edit(f"{lang('error_prefix')}{lang('profile_e_no')}") return first_name = user.first_name.replace("\u2060", "") - last_name = user.last_name.replace("\u2060", "") if user.last_name is not None else lang('profile_noset') - verified = lang('profile_yes') if user.is_verified else lang('profile_no') - restricted = lang('profile_yes') if user.is_restricted else lang('profile_no') - caption = f"**{lang('profile_name')}:** \n" \ - f"{lang('profile_username')}: {username_system} \n" \ - f"ID: {user.id} \n" \ - f"{lang('profile_fname')}: {first_name} \n" \ - f"{lang('profile_lname')}: {last_name} \n" \ - f"{lang('profile_verified')}: {verified} \n" \ - f"{lang('profile_restricted')}: {restricted} \n" \ - f"{lang('profile_type')}: {user_type} \n" \ - f"[{first_name}](tg://user?id={user.id})" + last_name = ( + user.last_name.replace("\u2060", "") + if user.last_name is not None + else lang("profile_noset") + ) + verified = lang("profile_yes") if user.is_verified else lang("profile_no") + restricted = lang("profile_yes") if user.is_restricted else lang("profile_no") + caption = ( + f"**{lang('profile_name')}:** \n" + f"{lang('profile_username')}: {username_system} \n" + f"ID: {user.id} \n" + f"{lang('profile_fname')}: {first_name} \n" + f"{lang('profile_lname')}: {last_name} \n" + f"{lang('profile_verified')}: {verified} \n" + f"{lang('profile_restricted')}: {restricted} \n" + f"{lang('profile_type')}: {user_type} \n" + f"[{first_name}](tg://user?id={user.id})" + ) photo = await client.download_media(user.photo.big_file_id) - reply_to = message.reply_to_message.id if message.reply_to_message else message.reply_to_top_message_id + reply_to = ( + message.reply_to_message.id + if message.reply_to_message + else message.reply_to_top_message_id + ) try: await client.send_photo( - message.chat.id, - photo, - caption=caption, - reply_to_message_id=reply_to + message.chat.id, photo, caption=caption, reply_to_message_id=reply_to ) await message.delete() return remove(photo) @@ -83,17 +101,21 @@ async def profile(client: Client, message: Message): await message.edit(caption) -@listener(is_plugin=False, outgoing=True, command="block", - need_admin=True, - description=lang('block_des'), - parameters="(username/uid/reply)") +@listener( + is_plugin=False, + outgoing=True, + command="block", + need_admin=True, + description=lang("block_des"), + parameters="(username/uid/reply)", +) async def block_user(client: Client, message: Message): - """ Block a user. """ + """Block a user.""" if len(message.parameter) > 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return if not Config.SILENT: - message = await message.edit(lang('block_process')) + message = await message.edit(lang("block_process")) user = message.obtain_user() if not user: return await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") @@ -103,17 +125,21 @@ async def block_user(client: Client, message: Message): await message.edit(f"`{user}` {lang('block_exist')}") -@listener(is_plugin=False, outgoing=True, command="unblock", - need_admin=True, - description=lang('unblock_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command="unblock", + need_admin=True, + description=lang("unblock_des"), + parameters="", +) async def unblock_user(client: Client, message: Message): - """ Unblock a user. """ + """Unblock a user.""" if len(message.parameter) > 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return if not Config.SILENT: - message = await message.edit(lang('unblock_process')) + message = await message.edit(lang("unblock_process")) user = message.obtain_user() if not user: return await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") diff --git a/pagermaid/modules/avoid.py b/pagermaid/modules/avoid.py index 3116728..dfacaf4 100644 --- a/pagermaid/modules/avoid.py +++ b/pagermaid/modules/avoid.py @@ -7,11 +7,15 @@ from pagermaid.enums import Client, Message from pagermaid.listener import listener -@listener(is_plugin=False, outgoing=True, command="ghost", - description=lang('ghost_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command="ghost", + description=lang("ghost_des"), + parameters="", +) async def ghost(client: Client, message: Message): - """ Toggles ghosting of a user. """ + """Toggles ghosting of a user.""" if len(message.parameter) != 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return @@ -19,35 +23,43 @@ async def ghost(client: Client, message: Message): self_user_id = myself.id if message.parameter[0] == "true": if message.chat.id == self_user_id: - return await message.edit(lang('ghost_e_mark')) + return await message.edit(lang("ghost_e_mark")) sqlite[f"ghosted.chat_id.{str(message.chat.id)}"] = True await message.safe_delete() - await log(f"{lang('ghost_set_f')} ChatID {str(message.chat.id)} {lang('ghost_set_l')}") + await log( + f"{lang('ghost_set_f')} ChatID {str(message.chat.id)} {lang('ghost_set_l')}" + ) elif message.parameter[0] == "false": if message.chat.id == self_user_id: - await message.edit(lang('ghost_e_mark')) + await message.edit(lang("ghost_e_mark")) return try: del sqlite[f"ghosted.chat_id.{str(message.chat.id)}"] except KeyError: - return await message.edit(lang('ghost_e_noexist')) + return await message.edit(lang("ghost_e_noexist")) await message.safe_delete() - await log(f"{lang('ghost_set_f')} ChatID {str(message.chat.id)} {lang('ghost_cancel')}") + await log( + f"{lang('ghost_set_f')} ChatID {str(message.chat.id)} {lang('ghost_cancel')}" + ) elif message.parameter[0] == "status": if sqlite.get(f"ghosted.chat_id.{str(message.chat.id)}", None): - await message.edit(lang('ghost_e_exist')) + await message.edit(lang("ghost_e_exist")) else: - await message.edit(lang('ghost_e_noexist')) + await message.edit(lang("ghost_e_noexist")) else: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") -@listener(is_plugin=False, outgoing=True, command="deny", - need_admin=True, - description=lang('deny_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command="deny", + need_admin=True, + description=lang("deny_des"), + parameters="", +) async def deny(client: Client, message: Message): - """ Toggles denying of a user. """ + """Toggles denying of a user.""" if len(message.parameter) != 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return @@ -55,38 +67,38 @@ async def deny(client: Client, message: Message): self_user_id = myself.id if message.parameter[0] == "true": if message.chat.id == self_user_id: - return await message.edit(lang('ghost_e_mark')) + return await message.edit(lang("ghost_e_mark")) sqlite[f"denied.chat_id.{str(message.chat.id)}"] = True await message.safe_delete() await log(f"ChatID {str(message.chat.id)} {lang('deny_set')}") elif message.parameter[0] == "false": if message.chat.id == self_user_id: - await message.edit(lang('ghost_e_mark')) + await message.edit(lang("ghost_e_mark")) return try: del sqlite[f"denied.chat_id.{str(message.chat.id)}"] except KeyError: - return await message.edit(lang('deny_e_noexist')) + return await message.edit(lang("deny_e_noexist")) await message.safe_delete() await log(f"ChatID {str(message.chat.id)} {lang('deny_cancel')}") elif message.parameter[0] == "status": if sqlite.get(f"denied.chat_id.{str(message.chat.id)}", None): - await message.edit(lang('deny_e_exist')) + await message.edit(lang("deny_e_exist")) else: - await message.edit(lang('deny_e_noexist')) + await message.edit(lang("deny_e_noexist")) else: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") @listener(is_plugin=False, incoming=True, outgoing=False, ignore_edited=True) async def set_read_acknowledgement(client: Client, message: Message): - """ Event handler to infinitely read ghosted messages. """ + """Event handler to infinitely read ghosted messages.""" if sqlite.get(f"ghosted.chat_id.{str(message.chat.id)}", None): await client.read_chat_history(message.chat.id) @listener(is_plugin=False, incoming=True, outgoing=False, ignore_edited=True) async def message_removal(message: Message): - """ Event handler to infinitely delete denied messages. """ + """Event handler to infinitely delete denied messages.""" if sqlite.get(f"denied.chat_id.{str(message.chat.id)}", None): await message.safe_delete() diff --git a/pagermaid/modules/backup.py b/pagermaid/modules/backup.py index 54b0688..066a187 100644 --- a/pagermaid/modules/backup.py +++ b/pagermaid/modules/backup.py @@ -39,10 +39,11 @@ def un_tar_gz(filename, dirs): return False -@listener(is_plugin=False, outgoing=True, command="backup", - description=lang('backup_des')) +@listener( + is_plugin=False, outgoing=True, command="backup", description=lang("backup_des") +) async def backup(message: Message): - await message.edit(lang('backup_process')) + await message.edit(lang("backup_process")) # Remove old backup if os.path.exists(pgm_backup_zip_name): @@ -50,7 +51,12 @@ async def backup(message: Message): # remove mp3 , they are so big ! for i in os.listdir("data"): - if i.find(".mp3") != -1 or i.find(".jpg") != -1 or i.find(".flac") != -1 or i.find(".ogg") != -1: + if ( + i.find(".mp3") != -1 + or i.find(".jpg") != -1 + or i.find(".flac") != -1 + or i.find(".ogg") != -1 + ): os.remove(f"data{os.sep}{i}") # run backup function @@ -65,37 +71,41 @@ async def backup(message: Message): await message.edit(lang("backup_success")) -@listener(is_plugin=False, outgoing=True, command="recovery", - need_admin=True, - description=lang('recovery_des')) +@listener( + is_plugin=False, + outgoing=True, + command="recovery", + need_admin=True, + description=lang("recovery_des"), +) async def recovery(message: Message): reply = message.reply_to_message if not reply: - return await message.edit(lang('recovery_file_error')) + return await message.edit(lang("recovery_file_error")) if not reply.document: - return await message.edit(lang('recovery_file_error')) + return await message.edit(lang("recovery_file_error")) try: if ".tar.gz" not in reply.document.file_name: - return await message.edit(lang('recovery_file_error')) - await message.edit(lang('recovery_down')) + return await message.edit(lang("recovery_file_error")) + await message.edit(lang("recovery_down")) # Start download process pgm_backup_zip_name = await reply.download() # noqa except Exception as e: # noqa print(e, format_exc()) - return await message.edit(lang('recovery_file_error')) + return await message.edit(lang("recovery_file_error")) # Extract backup files - await message.edit(lang('recovery_process')) + await message.edit(lang("recovery_process")) if not os.path.exists(pgm_backup_zip_name): - return await message.edit(lang('recovery_file_not_found')) + return await message.edit(lang("recovery_file_not_found")) elif not un_tar_gz(pgm_backup_zip_name, ""): os.remove(pgm_backup_zip_name) - return await message.edit(lang('recovery_file_error')) + return await message.edit(lang("recovery_file_error")) # Cleanup if os.path.exists(pgm_backup_zip_name): os.remove(pgm_backup_zip_name) - await message.edit(lang('recovery_success') + " " + lang('apt_reboot')) + await message.edit(lang("recovery_success") + " " + lang("apt_reboot")) sys.exit(0) diff --git a/pagermaid/modules/clock.py b/pagermaid/modules/clock.py index 7acc9b9..486b4bd 100644 --- a/pagermaid/modules/clock.py +++ b/pagermaid/modules/clock.py @@ -8,11 +8,15 @@ from pagermaid.listener import listener from pagermaid.utils import lang, Message -@listener(is_plugin=False, outgoing=True, command="time", - description=lang('time_des'), - parameters=lang('time_parameters')) +@listener( + is_plugin=False, + outgoing=True, + command="time", + description=lang("time_des"), + parameters=lang("time_parameters"), +) async def time(message: Message): - """ For querying time. """ + """For querying time.""" if len(message.parameter) == 1: country = message.parameter[0].title() else: @@ -37,24 +41,24 @@ async def time(message: Message): time_zone = await get_timezone(country) if not time_zone: if len(message.parameter) < 1: - await message.edit(lang('time_config')) + await message.edit(lang("time_config")) return try: time_num, utc_num = int(message.parameter[0]), int(message.parameter[0]) if time_num == 0: - time_num, utc_num = '', '' + time_num, utc_num = "", "" elif 0 < time_num < 13: - time_num, utc_num = f'-{time_num}', f'+{time_num}' + time_num, utc_num = f"-{time_num}", f"+{time_num}" elif -13 < time_num < 0: - time_num, utc_num = f'+{-time_num}', f'{time_num}' + time_num, utc_num = f"+{-time_num}", f"{time_num}" elif time_num < -12: - time_num, utc_num = '+12', '-12' + time_num, utc_num = "+12", "-12" elif time_num > 12: - time_num, utc_num = '-12', '+12' - time_zone = timezone(f'Etc/GMT{time_num}') - country_name = f'UTC{utc_num}' + time_num, utc_num = "-12", "+12" + time_zone = timezone(f"Etc/GMT{time_num}") + country_name = f"UTC{utc_num}" except ValueError: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) return else: try: @@ -62,13 +66,15 @@ async def time(message: Message): except KeyError: country_name = country - await message.edit(f"**{country_name} {lang('time_time')}:**\n" - f"`{datetime.now(time_zone).strftime(date_form)} " - f"{datetime.now(time_zone).strftime(time_form)}`") + await message.edit( + f"**{country_name} {lang('time_time')}:**\n" + f"`{datetime.now(time_zone).strftime(date_form)} " + f"{datetime.now(time_zone).strftime(time_form)}`" + ) async def get_timezone(target): - """ Returns timezone of the parameter in command. """ + """Returns timezone of the parameter in command.""" if "(Uk)" in target: target = target.replace("Uk", "UK") if "(Us)" in target: diff --git a/pagermaid/modules/help.py b/pagermaid/modules/help.py index 221914d..c8f7406 100644 --- a/pagermaid/modules/help.py +++ b/pagermaid/modules/help.py @@ -15,76 +15,138 @@ from pagermaid.listener import listener import pathlib -@listener(is_plugin=False, command="help", - description=lang('help_des'), - parameters=f"<{lang('command')}>") +@listener( + is_plugin=False, + command="help", + description=lang("help_des"), + parameters=f"<{lang('command')}>", +) async def help_command(message: Message): - """ The help new command,""" + """The help new command,""" if message.arguments: if message.arguments in help_messages: - if from_self(message) or \ - enforce_permission(from_msg_get_sudo_uid(message), help_messages[message.arguments]["permission"]): + if from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), + help_messages[message.arguments]["permission"], + ): await message.edit(f"{help_messages[message.arguments]['use']}") else: - await message.edit(lang('help_no_permission')) + await message.edit(lang("help_no_permission")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) else: result = f"**{lang('help_list')}: \n**" - support_commands = ['username', 'name', 'pfp', 'bio', 'rmpfp', - 'profile', 'block', 'unblock', 'ghost', 'deny', 'convert', - 'caption', 'ocr', 'highlight', 'time', 'translate', - 'tts', 'google', 'animate', - 'teletype', 'widen', 'owo', 'flip', - 'rng', 'aaa', 'tuxsay', 'coin', 'help', - 'lang', 'alias', 'id', 'uslog', 'log', - 're', 'leave', 'hitokoto', 'apt', 'prune', 'selfprune', - 'yourprune', 'del', 'genqr', 'parseqr', - 'sb', 'sysinfo', 'status', - 'stats', 'speedtest', 'connection', - 'pingdc', 'ping', 'topcloud', - 's', 'sticker', 'sh', 'restart', - 'trace', 'chat', 'update'] + support_commands = [ + "username", + "name", + "pfp", + "bio", + "rmpfp", + "profile", + "block", + "unblock", + "ghost", + "deny", + "convert", + "caption", + "ocr", + "highlight", + "time", + "translate", + "tts", + "google", + "animate", + "teletype", + "widen", + "owo", + "flip", + "rng", + "aaa", + "tuxsay", + "coin", + "help", + "lang", + "alias", + "id", + "uslog", + "log", + "re", + "leave", + "hitokoto", + "apt", + "prune", + "selfprune", + "yourprune", + "del", + "genqr", + "parseqr", + "sb", + "sysinfo", + "status", + "stats", + "speedtest", + "connection", + "pingdc", + "ping", + "topcloud", + "s", + "sticker", + "sh", + "restart", + "trace", + "chat", + "update", + ] for command in sorted(help_messages, reverse=False): if str(command) in support_commands: continue - if from_self(message) or \ - enforce_permission(from_msg_get_sudo_uid(message), help_messages[command]["permission"]): + if from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), help_messages[command]["permission"] + ): result += f"`{command}`, " if result == f"**{lang('help_list')}: \n**": - """ The help raw command,""" + """The help raw command,""" for command in sorted(help_messages, reverse=False): - if from_self(message) or \ - enforce_permission(from_msg_get_sudo_uid(message), help_messages[command]["permission"]): + if from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), help_messages[command]["permission"] + ): result += f"`{command}`, " - await message.edit(result[ - :-2] + f"\n**{lang('help_send')} \",help <{lang('command')}>\" {lang('help_see')}**\n" - f"[{lang('help_source')}](https://t.me/PagerMaid_Modify) " - f"[{lang('help_plugin')}](https://index.xtaolabs.com/) " - f"[{lang('help_module')}](https://wiki.xtaolabs.com/)", - parse_mode=ParseMode.MARKDOWN, - disable_web_page_preview=True) + await message.edit( + result[:-2] + + f"\n**{lang('help_send')} \",help <{lang('command')}>\" {lang('help_see')}**\n" + f"[{lang('help_source')}](https://t.me/PagerMaid_Modify) " + f"[{lang('help_plugin')}](https://index.xtaolabs.com/) " + f"[{lang('help_module')}](https://wiki.xtaolabs.com/)", + parse_mode=ParseMode.MARKDOWN, + disable_web_page_preview=True, + ) -@listener(is_plugin=False, command="help_raw", - description=lang('help_des'), - parameters=f"<{lang('command')}>") +@listener( + is_plugin=False, + command="help_raw", + description=lang("help_des"), + parameters=f"<{lang('command')}>", +) async def help_raw_command(message: Message): - """ The help raw command,""" + """The help raw command,""" if message.arguments: if message.arguments in help_messages: - if from_self(message) or \ - enforce_permission(from_msg_get_sudo_uid(message), help_messages[message.arguments]["permission"]): + if from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), + help_messages[message.arguments]["permission"], + ): await message.edit(f"{help_messages[message.arguments]['use']}") else: - await message.edit(lang('help_no_permission')) + await message.edit(lang("help_no_permission")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) else: result = f"**{lang('help_list')}: \n**" for command in sorted(help_messages, reverse=False): - if from_self(message) or \ - enforce_permission(from_msg_get_sudo_uid(message), help_messages[command]["permission"]): + if from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), help_messages[command]["permission"] + ): result += f"`{command}`, " await message.edit( f"""{result[:-2]}\n**{lang('help_send')} ",help <{lang('command')}>" {lang('help_see')}** [{lang('help_source')}](https://t.me/PagerMaid_Modify)""", @@ -93,57 +155,67 @@ async def help_raw_command(message: Message): ) -@listener(is_plugin=False, command="lang", - need_admin=True, - description=lang('lang_des')) +@listener( + is_plugin=False, command="lang", need_admin=True, description=lang("lang_des") +) async def lang_change(message: Message): to_lang = message.arguments from_lang = Config.LANGUAGE - dir_, dir__ = listdir('languages/built-in'), [] + dir_, dir__ = listdir("languages/built-in"), [] for i in dir_: - if i.find('yml') != -1: + if i.find("yml") != -1: dir__.append(i[:-4]) - file = pathlib.Path('config.yml').read_text() + file = pathlib.Path("config.yml").read_text() if to_lang in dir__: - file = file.replace(f'application_language: "{from_lang}"', f'application_language: "{to_lang}"') - with open('config.yml', 'w', encoding="utf-8") as f: + file = file.replace( + f'application_language: "{from_lang}"', f'application_language: "{to_lang}"' + ) + with open("config.yml", "w", encoding="utf-8") as f: f.write(file) await message.edit(f"{lang('lang_change_to')} {to_lang}, {lang('lang_reboot')}") await reload_all() else: - await message.edit(f'{lang("lang_current_lang")} {Config.LANGUAGE}\n\n' - f'{lang("lang_all_lang")}{",".join(dir__)}') + await message.edit( + f'{lang("lang_current_lang")} {Config.LANGUAGE}\n\n' + f'{lang("lang_all_lang")}{",".join(dir__)}' + ) -@listener(is_plugin=False, outgoing=True, command="alias", - disallow_alias=True, - need_admin=True, - description=lang('alias_des'), - parameters='{list|del|set} ') +@listener( + is_plugin=False, + outgoing=True, + command="alias", + disallow_alias=True, + need_admin=True, + description=lang("alias_des"), + parameters="{list|del|set} ", +) async def alias_commands(message: Message): alias_manager = AliasManager() if len(message.parameter) == 0: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif len(message.parameter) == 1: if alias_manager.alias_list: - await message.edit(lang('alias_list') + '\n\n' + alias_manager.get_all_alias_text()) + await message.edit( + lang("alias_list") + "\n\n" + alias_manager.get_all_alias_text() + ) else: - await message.edit(lang('alias_no')) + await message.edit(lang("alias_no")) elif len(message.parameter) == 2: source_command = message.parameter[1] try: alias_manager.delete_alias(source_command) - await message.edit(lang('alias_success')) + await message.edit(lang("alias_success")) await reload_all() except KeyError: - await message.edit(lang('alias_no_exist')) + await message.edit(lang("alias_no_exist")) return elif len(message.parameter) == 3: source_command = message.parameter[1] to_command = message.parameter[2] if to_command in help_messages: - await message.edit(lang('alias_exist')) + await message.edit(lang("alias_exist")) return alias_manager.add_alias(source_command, to_command) - await message.edit(lang('alias_success')) + await message.edit(lang("alias_success")) await reload_all() diff --git a/pagermaid/modules/message.py b/pagermaid/modules/message.py index 7463e4c..4ee27dd 100644 --- a/pagermaid/modules/message.py +++ b/pagermaid/modules/message.py @@ -10,10 +10,9 @@ from pagermaid.utils import lang from pagermaid.enums import Client, Message -@listener(is_plugin=False, outgoing=True, command="id", - description=lang("id_des")) +@listener(is_plugin=False, outgoing=True, command="id", description=lang("id_des")) async def userid(message: Message): - """ Query the UserID of the sender of the message you replied to. """ + """Query the UserID of the sender of the message you replied to.""" reply = message.reply_to_message text = f"Message ID: `{str(message.id)}" + "`\n\n" text += "**Chat**\nid:`" + str(message.chat.id) + "`\n" @@ -36,7 +35,7 @@ async def userid(message: Message): return await message.edit(lang("leave_not_group")) text += f"protected: `{str(msg_from.has_protected_content)}" + "`\n" if reply: - text += "\n" + lang('id_hint') + "\nMessage ID: `" + str(reply.id) + "`" + text += "\n" + lang("id_hint") + "\nMessage ID: `" + str(reply.id) + "`" try: text += "\n\n**User**\nid: `" + str(reply.from_user.id) + "`" if reply.from_user.is_bot: @@ -61,9 +60,14 @@ async def userid(message: Message): except AttributeError: pass if reply.forward_from_chat: - text += "\n\n**Forward From Channel**\n" \ - "id: `" + str(reply.forward_from_chat.id) + \ - "`\ntitle: `" + reply.forward_from_chat.title + "`" + text += ( + "\n\n**Forward From Channel**\n" + "id: `" + + str(reply.forward_from_chat.id) + + "`\ntitle: `" + + reply.forward_from_chat.title + + "`" + ) if reply.forward_from_chat.username: text += "\nusername: @" + reply.forward_from_chat.username if reply.forward_from_message_id: @@ -71,7 +75,9 @@ async def userid(message: Message): if reply.forward_sender_name: text += "\npost_author: `" + reply.forward_sender_name + "`" elif reply.forward_from: - text += "\n\n**Forward From User**\nid: `" + str(reply.forward_from.id) + "`" + text += ( + "\n\n**Forward From User**\nid: `" + str(reply.forward_from.id) + "`" + ) try: if reply.forward_from.is_bot: text += f"\nis_bot: {lang('id_is_bot_yes')}" @@ -88,15 +94,23 @@ async def userid(message: Message): except AttributeError: pass elif reply.forward_sender_name: - text += "\n\n**Forward From User**\nsender_name: `" + str(reply.forward_sender_name) + "`" + text += ( + "\n\n**Forward From User**\nsender_name: `" + + str(reply.forward_sender_name) + + "`" + ) await message.edit(text) -@listener(is_plugin=False, outgoing=True, command="uslog", - description=lang('uslog_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command="uslog", + description=lang("uslog_des"), + parameters="", +) async def uslog(message: Message): - """ Forwards a message into log group """ + """Forwards a message into log group""" if Config.LOG: if message.reply_to_message: reply_msg = message.reply_to_message @@ -104,17 +118,21 @@ async def uslog(message: Message): elif message.arguments: await log(message.arguments) else: - return await message.edit(lang('arg_error')) - await message.edit(lang('uslog_success')) + return await message.edit(lang("arg_error")) + await message.edit(lang("uslog_success")) else: - await message.edit(lang('uslog_log_disable')) + await message.edit(lang("uslog_log_disable")) -@listener(is_plugin=False, outgoing=True, command="log", - description=lang('log_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command="log", + description=lang("log_des"), + parameters="", +) async def logging(message: Message): - """ Forwards a message into log group """ + """Forwards a message into log group""" if Config.LOG: if message.reply_to_message: reply_msg = message.reply_to_message @@ -122,38 +140,45 @@ async def logging(message: Message): elif message.arguments: await log(message.arguments) else: - return await message.edit(lang('arg_error')) + return await message.edit(lang("arg_error")) await message.safe_delete() else: - await message.edit(lang('uslog_log_disable')) + await message.edit(lang("uslog_log_disable")) -@listener(is_plugin=False, outgoing=True, command="re", - description=lang('re_des'), - parameters=lang('re_parameters')) +@listener( + is_plugin=False, + outgoing=True, + command="re", + description=lang("re_des"), + parameters=lang("re_parameters"), +) async def re(bot: Client, message: Message): - """ Forwards a message into this group """ + """Forwards a message into this group""" if reply := message.reply_to_message: - if message.arguments == '': + if message.arguments == "": num = 1 else: try: num = int(message.arguments) if num > 100: - await message.edit(lang('re_too_big')) + await message.edit(lang("re_too_big")) except Exception: - return await message.edit(lang('re_arg_error')) + return await message.edit(lang("re_arg_error")) await message.safe_delete() for _ in range(num): try: if not message.chat.has_protected_content: await forward_msg(bot, message.reply_to_message) else: - await reply.copy(reply.chat.id, reply_to_message_id=message.reply_to_top_message_id) + await reply.copy( + reply.chat.id, + reply_to_message_id=message.reply_to_top_message_id, + ) except (Forbidden, FloodWait, Exception): return else: - await message.edit(lang('not_reply')) + await message.edit(lang("not_reply")) async def forward_msg(bot: Client, message: Message): diff --git a/pagermaid/modules/mixpanel.py b/pagermaid/modules/mixpanel.py index 102d012..a9cd80e 100644 --- a/pagermaid/modules/mixpanel.py +++ b/pagermaid/modules/mixpanel.py @@ -13,7 +13,7 @@ from pagermaid.hook import Hook class DatetimeSerializer(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): - fmt = '%Y-%m-%dT%H:%M:%S' + fmt = "%Y-%m-%dT%H:%M:%S" return obj.strftime(fmt) return json.JSONEncoder.default(self, obj) @@ -37,57 +37,57 @@ class Mixpanel: @staticmethod def json_dumps(data, cls=None): # Separators are specified to eliminate whitespace. - return json.dumps(data, separators=(',', ':'), cls=cls) + return json.dumps(data, separators=(",", ":"), cls=cls) async def api_call(self, endpoint, json_message): _endpoints = { - 'events': f'https://{self.api_host}/track', - 'people': f'https://{self.api_host}/engage', + "events": f"https://{self.api_host}/track", + "people": f"https://{self.api_host}/engage", } request_url = _endpoints.get(endpoint) if request_url is None: return params = { - 'data': json_message, - 'verbose': 1, - 'ip': 0, + "data": json_message, + "verbose": 1, + "ip": 0, } start = self._now() with contextlib.suppress(Exception): - await self._request.post( - request_url, - data=params, - timeout=10.0 - ) + await self._request.post(request_url, data=params, timeout=10.0) logs.debug(f"Mixpanel request took {self._now() - start} seconds") async def people_set(self, distinct_id: str, properties: dict): message = { - '$distinct_id': distinct_id, - '$set': properties, + "$distinct_id": distinct_id, + "$set": properties, } - record = {'$token': self._token, '$time': self._now()} + record = {"$token": self._token, "$time": self._now()} # sourcery skip: dict-assign-update-to-union record.update(message) - return await self.api_call('people', self.json_dumps(record, cls=self._serializer)) + return await self.api_call( + "people", self.json_dumps(record, cls=self._serializer) + ) async def track(self, distinct_id: str, event_name: str, properties: dict): all_properties = { - 'token': self._token, - 'distinct_id': distinct_id, - 'time': self._now(), - '$insert_id': self._make_insert_id(), - 'mp_lib': 'python', - '$lib_version': '4.10.0', + "token": self._token, + "distinct_id": distinct_id, + "time": self._now(), + "$insert_id": self._make_insert_id(), + "mp_lib": "python", + "$lib_version": "4.10.0", } if properties: # sourcery skip: dict-assign-update-to-union all_properties.update(properties) event = { - 'event': event_name, - 'properties': all_properties, + "event": event_name, + "properties": all_properties, } - return await self.api_call('events', self.json_dumps(event, cls=self._serializer)) + return await self.api_call( + "events", self.json_dumps(event, cls=self._serializer) + ) mp = Mixpanel(Config.MIXPANEL_API) @@ -97,7 +97,7 @@ mp = Mixpanel(Config.MIXPANEL_API) async def mixpanel_init_id(bot: Client): if not bot.me: bot.me = await bot.get_me() - data = {'$first_name': bot.me.first_name} + data = {"$first_name": bot.me.first_name} if bot.me.username: data["username"] = bot.me.username bot.loop.create_task(mp.people_set(str(bot.me.id), data)) @@ -113,4 +113,10 @@ async def mixpanel_report(bot: Client, message: Message, command): sender_id = message.sender_chat.id if message.sender_chat else sender_id if sender_id < 0 and message.outgoing: sender_id = bot.me.id - bot.loop.create_task(mp.track(str(sender_id), f'Function {command}', {'command': command, "bot_id": bot.me.id})) + bot.loop.create_task( + mp.track( + str(sender_id), + f"Function {command}", + {"command": command, "bot_id": bot.me.id}, + ) + ) diff --git a/pagermaid/modules/plugin.py b/pagermaid/modules/plugin.py index cefc5fa..d9ce523 100644 --- a/pagermaid/modules/plugin.py +++ b/pagermaid/modules/plugin.py @@ -33,50 +33,56 @@ def move_plugin(file_path): def update_version(plugin_name, version): plugin_directory = f"{working_dir}{sep}plugins{sep}" - with open(f"{plugin_directory}version.json", 'r', encoding="utf-8") as f: + with open(f"{plugin_directory}version.json", "r", encoding="utf-8") as f: version_json = json.load(f) version_json[plugin_name] = version - with open(f"{plugin_directory}version.json", 'w') as f: + with open(f"{plugin_directory}version.json", "w") as f: json.dump(version_json, f) -@listener(is_plugin=False, outgoing=True, command="apt", - need_admin=True, - diagnostics=False, - description=lang('apt_des'), - parameters=lang('apt_parameters')) +@listener( + is_plugin=False, + outgoing=True, + command="apt", + need_admin=True, + diagnostics=False, + description=lang("apt_des"), + parameters=lang("apt_parameters"), +) async def plugin(message: Message): if len(message.parameter) == 0: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) return reply = message.reply_to_message plugin_directory = f"{working_dir}{sep}plugins{sep}" if message.parameter[0] == "install": if len(message.parameter) == 1: - message = await message.edit(lang('apt_processing')) + message = await message.edit(lang("apt_processing")) file_path = None with contextlib.suppress(Exception): if reply: file_path = await reply.download() else: file_path = await message.download() - if file_path is None or not file_path.endswith('.py'): - await message.edit(lang('apt_no_py')) + if file_path is None or not file_path.endswith(".py"): + await message.edit(lang("apt_no_py")) try: remove(str(file_path)) except FileNotFoundError: pass return move_plugin(file_path) - await message.edit(f"{lang('apt_name')}\n\n" - f"{lang('apt_plugin')} " - f"{path.basename(file_path)[:-3]} {lang('apt_installed')}") + await message.edit( + f"{lang('apt_name')}\n\n" + f"{lang('apt_plugin')} " + f"{path.basename(file_path)[:-3]} {lang('apt_installed')}" + ) await log(f"{lang('apt_install_success')} {path.basename(file_path)[:-3]}.") await reload_all() elif len(message.parameter) >= 2: await plugin_manager.load_remote_plugins() process_list = message.parameter - message = await message.edit(lang('apt_processing')) + message = await message.edit(lang("apt_processing")) del process_list[0] success_list = [] failed_list = [] @@ -98,30 +104,34 @@ async def plugin(message: Message): failed_list.append(i) text = f"{lang('apt_name')}\n\n" if len(success_list) > 0: - text += lang('apt_install_success') + " : %s\n" % ", ".join(success_list) + text += lang("apt_install_success") + " : %s\n" % ", ".join( + success_list + ) if len(failed_list) > 0: - text += lang('apt_not_found') + " %s\n" % ", ".join(failed_list) + text += lang("apt_not_found") + " %s\n" % ", ".join(failed_list) if len(no_need_list) > 0: - text += lang('apt_no_update') + " %s\n" % ", ".join(no_need_list) + text += lang("apt_no_update") + " %s\n" % ", ".join(no_need_list) await log(text) restart = len(success_list) > 0 await message.edit(text) if restart: await reload_all() else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "remove": if len(message.parameter) == 2: if plugin_manager.remove_plugin(message.parameter[1]): - await message.edit(f"{lang('apt_remove_success')} {message.parameter[1]}") + await message.edit( + f"{lang('apt_remove_success')} {message.parameter[1]}" + ) await log(f"{lang('apt_remove')} {message.parameter[1]}.") await reload_all() elif "/" in message.parameter[1]: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) else: - await message.edit(lang('apt_not_exist')) + await message.edit(lang("apt_not_exist")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "status": if len(message.parameter) == 1: inactive_plugins = sorted(__list_plugins()) @@ -151,35 +161,41 @@ async def plugin(message: Message): inactive_plugins_string = f"`{lang('apt_no_load_failed_plugins')}`" if len(disabled_plugins) == 0: disabled_plugins_string = f"`{lang('apt_no_disabled_plugins')}`" - output = f"**{lang('apt_plugin_list')}**\n" \ - f"{lang('apt_plugin_running')}: {active_plugins_string}\n" \ - f"{lang('apt_plugin_disabled')}: {disabled_plugins_string}\n" \ - f"{lang('apt_plugin_failed')}: {inactive_plugins_string}" + output = ( + f"**{lang('apt_plugin_list')}**\n" + f"{lang('apt_plugin_running')}: {active_plugins_string}\n" + f"{lang('apt_plugin_disabled')}: {disabled_plugins_string}\n" + f"{lang('apt_plugin_failed')}: {inactive_plugins_string}" + ) await message.edit(output) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "enable": if len(message.parameter) == 2: if plugin_manager.enable_plugin(message.parameter[1]): - await message.edit(f"{lang('apt_plugin')} {message.parameter[1]} " - f"{lang('apt_enable')}") + await message.edit( + f"{lang('apt_plugin')} {message.parameter[1]} " + f"{lang('apt_enable')}" + ) await log(f"{lang('apt_enable')} {message.parameter[1]}.") await reload_all() else: - await message.edit(lang('apt_not_exist')) + await message.edit(lang("apt_not_exist")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "disable": if len(message.parameter) == 2: if plugin_manager.disable_plugin(message.parameter[1]): - await message.edit(f"{lang('apt_plugin')} {message.parameter[1]} " - f"{lang('apt_disable')}") + await message.edit( + f"{lang('apt_plugin')} {message.parameter[1]} " + f"{lang('apt_disable')}" + ) await log(f"{lang('apt_disable')} {message.parameter[1]}.") await reload_all() else: - await message.edit(lang('apt_not_exist')) + await message.edit(lang("apt_not_exist")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "upload": if len(message.parameter) == 2: file_name = f"{message.parameter[1]}.py" @@ -191,31 +207,41 @@ async def plugin(message: Message): elif exists(f"{plugin_directory}{file_name}.disabled"): copyfile(f"{plugin_directory}{file_name}.disabled", file_name) if exists(file_name): - await message.edit(lang('apt_uploading')) - await upload_attachment(file_name, - message.chat.id, reply_id, - thumb=f"pagermaid{sep}assets{sep}logo.jpg", - caption=f"{lang('apt_name')}\n\n" - f"PagerMaid-Pyro {message.parameter[1]} plugin.") + await message.edit(lang("apt_uploading")) + await upload_attachment( + file_name, + message.chat.id, + reply_id, + thumb=f"pagermaid{sep}assets{sep}logo.jpg", + caption=f"{lang('apt_name')}\n\n" + f"PagerMaid-Pyro {message.parameter[1]} plugin.", + ) remove(file_name) await message.safe_delete() else: - await message.edit(lang('apt_not_exist')) + await message.edit(lang("apt_not_exist")) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "update": if not exists(f"{plugin_directory}version.json"): - await message.edit(lang('apt_why_not_install_a_plugin')) + await message.edit(lang("apt_why_not_install_a_plugin")) return await plugin_manager.load_remote_plugins() - updated_plugins = [i.name for i in await plugin_manager.update_all_remote_plugin() if i] + updated_plugins = [ + i.name for i in await plugin_manager.update_all_remote_plugin() if i + ] if len(updated_plugins) == 0: - await message.edit(f"{lang('apt_name')}\n\n" + - lang("apt_loading_from_online_but_nothing_need_to_update")) + await message.edit( + f"{lang('apt_name')}\n\n" + + lang("apt_loading_from_online_but_nothing_need_to_update") + ) else: message = await message.edit(lang("apt_loading_from_online_and_updating")) await message.edit( - f"{lang('apt_name')}\n\n" + lang("apt_reading_list") + "\n" + "、".join(updated_plugins) + f"{lang('apt_name')}\n\n" + + lang("apt_reading_list") + + "\n" + + "、".join(updated_plugins) ) await reload_all() elif message.parameter[0] == "search": @@ -228,13 +254,25 @@ async def plugin(message: Message): plugin_online = plugin_list.json()["list"] for i in plugin_online: if search(plugin_name, i["name"], I): - search_result.extend(['`' + i['name'] + '` / `' + i['version'] + '`\n ' + i['des-short']]) + search_result.extend( + [ + "`" + + i["name"] + + "` / `" + + i["version"] + + "`\n " + + i["des-short"] + ] + ) if len(search_result) == 0: await message.edit(lang("apt_search_not_found")) else: - await message.edit(f"{lang('apt_search_result_hint')}:\n\n" + '\n\n'.join(search_result)) + await message.edit( + f"{lang('apt_search_result_hint')}:\n\n" + + "\n\n".join(search_result) + ) else: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) elif message.parameter[0] == "show": if len(message.parameter) == 1: await message.edit(lang("apt_search_no_name")) @@ -249,15 +287,17 @@ async def plugin(message: Message): search_support = lang("apt_search_supporting") else: search_support = lang("apt_search_not_supporting") - search_result = f"{lang('apt_plugin_name')}:`{i['name']}`\n" \ - f"{lang('apt_plugin_ver')}:`Ver {i['version']}`\n" \ - f"{lang('apt_plugin_section')}:`{i['section']}`\n" \ - f"{lang('apt_plugin_maintainer')}:`{i['maintainer']}`\n" \ - f"{lang('apt_plugin_size')}:`{i['size']}`\n" \ - f"{lang('apt_plugin_support')}:{search_support}\n" \ - f"{lang('apt_plugin_des_short')}:{i['des-short']}" + search_result = ( + f"{lang('apt_plugin_name')}:`{i['name']}`\n" + f"{lang('apt_plugin_ver')}:`Ver {i['version']}`\n" + f"{lang('apt_plugin_section')}:`{i['section']}`\n" + f"{lang('apt_plugin_maintainer')}:`{i['maintainer']}`\n" + f"{lang('apt_plugin_size')}:`{i['size']}`\n" + f"{lang('apt_plugin_support')}:{search_support}\n" + f"{lang('apt_plugin_des_short')}:{i['des-short']}" + ) break - if search_result == '': + if search_result == "": await message.edit(lang("apt_search_not_found")) else: await message.edit(search_result) @@ -267,7 +307,7 @@ async def plugin(message: Message): return message = await message.edit(lang("stats_loading")) list_plugin = [] - with open(f"{plugin_directory}version.json", 'r', encoding="utf-8") as f: + with open(f"{plugin_directory}version.json", "r", encoding="utf-8") as f: version_json = json.load(f) plugin_list = await client.get(f"{Config.GIT_SOURCE}list.json") plugin_online = plugin_list.json()["list"] diff --git a/pagermaid/modules/prune.py b/pagermaid/modules/prune.py index ffde71f..63d108f 100644 --- a/pagermaid/modules/prune.py +++ b/pagermaid/modules/prune.py @@ -10,20 +10,26 @@ from pagermaid.utils import lang import contextlib -@listener(is_plugin=False, outgoing=True, command="prune", - need_admin=True, - description=lang('prune_des')) +@listener( + is_plugin=False, + outgoing=True, + command="prune", + need_admin=True, + description=lang("prune_des"), +) async def prune(client: Client, message: Message): - """ Purge every single message after the message you replied to. """ + """Purge every single message after the message you replied to.""" if not message.reply_to_message: - await message.edit(lang('not_reply')) + await message.edit(lang("not_reply")) return input_chat = message.chat.id messages = [] count = 0 limit = message.id - message.reply_to_message.id + 1 if message.reply_to_top_message_id: - func = client.get_discussion_replies(input_chat, message.reply_to_top_message_id, limit=limit) + func = client.get_discussion_replies( + input_chat, message.reply_to_top_message_id, limit=limit + ) else: func = client.get_chat_history(input_chat, limit=limit) async for msg in func: @@ -45,24 +51,28 @@ async def prune(client: Client, message: Message): await notification.delete() -@listener(is_plugin=False, outgoing=True, command="selfprune", - need_admin=True, - description=lang('sp_des'), - parameters=lang('sp_parameters')) +@listener( + is_plugin=False, + outgoing=True, + command="selfprune", + need_admin=True, + description=lang("sp_des"), + parameters=lang("sp_parameters"), +) async def self_prune(bot: Client, message: Message): - """ Deletes specific amount of messages you sent. """ + """Deletes specific amount of messages you sent.""" msgs = [] count_buffer = 0 offset = 0 if len(message.parameter) != 1: if not message.reply_to_message: - return await message.edit(lang('arg_error')) + return await message.edit(lang("arg_error")) offset = message.reply_to_message.id try: count = int(message.parameter[0]) await message.delete() except ValueError: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) return async for msg in bot.get_chat_history(message.chat.id, limit=100): if count_buffer == count: @@ -73,7 +83,9 @@ async def self_prune(bot: Client, message: Message): if len(msgs) == 100: await bot.delete_messages(message.chat.id, msgs) msgs = [] - async for msg in bot.search_messages(message.chat.id, from_user="me", offset=offset): + async for msg in bot.search_messages( + message.chat.id, from_user="me", offset=offset + ): if count_buffer == count: break msgs.append(msg.id) @@ -93,25 +105,29 @@ async def self_prune(bot: Client, message: Message): await notification.delete() -@listener(is_plugin=False, outgoing=True, command="yourprune", - need_admin=True, - description=lang('yp_des'), - parameters=lang('sp_parameters')) +@listener( + is_plugin=False, + outgoing=True, + command="yourprune", + need_admin=True, + description=lang("yp_des"), + parameters=lang("sp_parameters"), +) async def your_prune(bot: Client, message: Message): - """ Deletes specific amount of messages someone sent. """ + """Deletes specific amount of messages someone sent.""" if not message.reply_to_message: - return await message.edit(lang('not_reply')) + return await message.edit(lang("not_reply")) target = message.reply_to_message if not target.from_user: - return await message.edit(lang('not_reply')) + return await message.edit(lang("not_reply")) if len(message.parameter) != 1: - return await message.edit(lang('arg_error')) + return await message.edit(lang("arg_error")) count = 0 try: count = int(message.parameter[0]) await message.delete() except ValueError: - return await message.edit(lang('arg_error')) + return await message.edit(lang("arg_error")) except Exception: # noqa pass count_buffer = 0 @@ -125,7 +141,9 @@ async def your_prune(bot: Client, message: Message): if len(msgs) == 100: await bot.delete_messages(message.chat.id, msgs) msgs = [] - async for msg in bot.search_messages(message.chat.id, from_user=target.from_user.id): + async for msg in bot.search_messages( + message.chat.id, from_user=target.from_user.id + ): if count_buffer == count: break count_buffer += 1 @@ -145,16 +163,20 @@ async def your_prune(bot: Client, message: Message): await notification.delete() -@listener(is_plugin=False, outgoing=True, command="del", - need_admin=True, - description=lang('del_des')) +@listener( + is_plugin=False, + outgoing=True, + command="del", + need_admin=True, + description=lang("del_des"), +) async def delete(message: Message): - """ Deletes the message you replied to. """ + """Deletes the message you replied to.""" if target := message.reply_to_message: with contextlib.suppress(Exception): await target.delete() await message.delete() - await log(lang('del_notification')) + await log(lang("del_notification")) else: await message.delete() diff --git a/pagermaid/modules/reload.py b/pagermaid/modules/reload.py index 057a587..069d95a 100644 --- a/pagermaid/modules/reload.py +++ b/pagermaid/modules/reload.py @@ -6,11 +6,11 @@ from pagermaid.services import scheduler from pagermaid.utils import lang -@listener(is_plugin=False, command="reload", - need_admin=True, - description=lang('reload_des')) +@listener( + is_plugin=False, command="reload", need_admin=True, description=lang("reload_des") +) async def reload_plugins(message: Message): - """ To reload plugins. """ + """To reload plugins.""" await reload_all() await message.edit(lang("reload_ok")) diff --git a/pagermaid/modules/sentry.py b/pagermaid/modules/sentry.py index 3cfe2ba..429e91b 100644 --- a/pagermaid/modules/sentry.py +++ b/pagermaid/modules/sentry.py @@ -17,7 +17,7 @@ def sentry_before_send(event, hint): exc_info = hint.get("exc_info") if exc_info and isinstance(exc_info[1], (Unauthorized, UsernameInvalid)): # The user has been deleted/deactivated or session revoked - safe_remove('pagermaid.session') + safe_remove("pagermaid.session") exit(1) if time() <= sentry_sdk_report_time + 30: sentry_sdk_report_time = time() @@ -28,7 +28,9 @@ def sentry_before_send(event, hint): sentry_sdk_report_time = time() -sentry_sdk_git_hash = run("git rev-parse HEAD", stdout=PIPE, shell=True).stdout.decode().strip() +sentry_sdk_git_hash = ( + run("git rev-parse HEAD", stdout=PIPE, shell=True).stdout.decode().strip() +) sentry_sdk.init( Config.SENTRY_API, traces_sample_rate=1.0, @@ -55,9 +57,14 @@ async def sentry_init_id(bot: Client): async def sentry_report(message: Message, command, exc_info, **_): sender_id = message.from_user.id if message.from_user else "" sender_id = message.sender_chat.id if message.sender_chat else sender_id - sentry_sdk.set_context("Target", {"ChatID": str(message.chat.id), - "UserID": str(sender_id), - "Msg": message.text or ""}) + sentry_sdk.set_context( + "Target", + { + "ChatID": str(message.chat.id), + "UserID": str(sender_id), + "Msg": message.text or "", + }, + ) if command: sentry_sdk.set_tag("com", command) sentry_sdk.capture_exception(exc_info) diff --git a/pagermaid/modules/status.py b/pagermaid/modules/status.py index 3dec06d..edb7758 100644 --- a/pagermaid/modules/status.py +++ b/pagermaid/modules/status.py @@ -29,43 +29,41 @@ DCs = { 2: "149.154.167.51", 3: "149.154.175.100", 4: "149.154.167.91", - 5: "91.108.56.130" + 5: "91.108.56.130", } -@listener(is_plugin=False, command="sysinfo", - description=lang('sysinfo_des')) +@listener(is_plugin=False, command="sysinfo", description=lang("sysinfo_des")) async def sysinfo(message: Message): - """ Retrieve system information via neofetch. """ + """Retrieve system information via neofetch.""" if not Config.SILENT: message = await message.edit(lang("sysinfo_loading")) - if platform == 'win32': + if platform == "win32": return await message.edit(neofetch_win(), parse_mode=ParseMode.HTML) result = await execute("neofetch --config none --stdout") await message.edit(f"`{result}`") -@listener(is_plugin=False, command="status", - description=lang('status_des')) +@listener(is_plugin=False, command="status", description=lang("status_des")) async def status(message: Message): # database # database = lang('status_online') if redis_status() else lang('status_offline') # uptime https://gist.github.com/borgstrom/936ca741e885a1438c374824efb038b3 uptime = await get_bot_uptime() - text = (f"**{lang('status_hint')}** \n" - f"{lang('status_name')}: `{uname().node}` \n" - f"{lang('status_platform')}: `{platform}` \n" - f"{lang('status_release')}: `{uname().release}` \n" - f"{lang('status_python')}: `{python_version()}` \n" - f"{lang('status_pyrogram')}: `{__version__}` \n" - f"{lang('status_pgm')}: `{pgm_version}`\n" - f"{lang('status_uptime')}: `{uptime}`" - ) + text = ( + f"**{lang('status_hint')}** \n" + f"{lang('status_name')}: `{uname().node}` \n" + f"{lang('status_platform')}: `{platform}` \n" + f"{lang('status_release')}: `{uname().release}` \n" + f"{lang('status_python')}: `{python_version()}` \n" + f"{lang('status_pyrogram')}: `{__version__}` \n" + f"{lang('status_pgm')}: `{pgm_version}`\n" + f"{lang('status_uptime')}: `{uptime}`" + ) await message.edit(text) -@listener(is_plugin=False, command="stats", - description=lang("stats_des")) +@listener(is_plugin=False, command="stats", description=lang("stats_des")) async def stats(client: Client, message: Message): msg = await message.edit(lang("stats_loading")) a, u, g, s, c, b = 0, 0, 0, 0, 0, 0 @@ -82,21 +80,21 @@ async def stats(client: Client, message: Message): elif chat_type == ChatType.CHANNEL: c += 1 a += 1 - text = (f"**{lang('stats_hint')}** \n" - f"{lang('stats_dialogs')}: `{a}` \n" - f"{lang('stats_private')}: `{u}` \n" - f"{lang('stats_group')}: `{g}` \n" - f"{lang('stats_supergroup')}: `{s}` \n" - f"{lang('stats_channel')}: `{c}` \n" - f"{lang('stats_bot')}: `{b}`" - ) + text = ( + f"**{lang('stats_hint')}** \n" + f"{lang('stats_dialogs')}: `{a}` \n" + f"{lang('stats_private')}: `{u}` \n" + f"{lang('stats_group')}: `{g}` \n" + f"{lang('stats_supergroup')}: `{s}` \n" + f"{lang('stats_channel')}: `{c}` \n" + f"{lang('stats_bot')}: `{b}`" + ) await msg.edit(text) -@listener(is_plugin=False, command="pingdc", - description=lang("pingdc_des")) +@listener(is_plugin=False, command="pingdc", description=lang("pingdc_des")) async def ping_dc(message: Message): - """ Ping your or other data center's IP addresses. """ + """Ping your or other data center's IP addresses.""" data = [] print("1") for dc in range(1, 6): @@ -107,7 +105,9 @@ async def ping_dc(message: Message): else: data.append("0") else: - result = await execute(f"ping -c 1 {DCs[dc]} | awk -F '/' " + "'END {print $5}'") + result = await execute( + f"ping -c 1 {DCs[dc]} | awk -F '/' " + "'END {print $5}'" + ) try: data.append(str(float(result))) except ValueError: @@ -121,10 +121,9 @@ async def ping_dc(message: Message): ) -@listener(is_plugin=False, command="ping", - description=lang("ping_des")) +@listener(is_plugin=False, command="ping", description=lang("ping_des")) async def ping(client: Client, message: Message): - """ Calculates latency between PagerMaid and Telegram. """ + """Calculates latency between PagerMaid and Telegram.""" start = datetime.now() await client.invoke(Ping(ping_id=0)) end = datetime.now() @@ -137,7 +136,7 @@ async def ping(client: Client, message: Message): def wmic(command: str): - """ Fetch the wmic command to cmd """ + """Fetch the wmic command to cmd""" try: p = Popen(command.split(" "), stdout=PIPE) except FileNotFoundError: @@ -152,7 +151,7 @@ def wmic(command: str): def get_uptime(): - """ Get the device uptime """ + """Get the device uptime""" delta = round(time() - boot_time()) hours, remainder = divmod(int(delta), 3600) @@ -179,17 +178,17 @@ def get_uptime(): return output -def readable(num, suffix='B'): - """ Convert Bytes into human-readable formats """ - for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']: +def readable(num, suffix="B"): + """Convert Bytes into human-readable formats""" + for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 - return "%.1f%s%s" % (num, 'Yi', suffix) + return "%.1f%s%s" % (num, "Yi", suffix) def get_ram(): - """ Get RAM used/free/total """ + """Get RAM used/free/total""" ram = virtual_memory() used = readable(ram.used) total = readable(ram.total) @@ -200,7 +199,7 @@ def get_ram(): def partitions(): - """ Find the disk partitions on current OS """ + """Find the disk partitions on current OS""" parts = disk_partitions() listparts = [] @@ -208,7 +207,9 @@ def partitions(): try: total, used, free = disk_usage(g.device) percent_used = round(used / total * 100, 2) - listparts.append(f" {g.device[:2]} {readable(used)} / {readable(total)} ({percent_used}%)") + listparts.append( + f" {g.device[:2]} {readable(used)} / {readable(total)} ({percent_used}%)" + ) except PermissionError: continue @@ -228,11 +229,11 @@ def neofetch_win(): mboard = "Unknown..." cpu = wmic("wmic cpu get name")[-1] gpu = wmic("wmic path win32_VideoController get name") - gpu = [f' {g.strip()}' for g in gpu[1:]][0].strip() + gpu = [f" {g.strip()}" for g in gpu[1:]][0].strip() ram = get_ram() - disks = '\n'.join(partitions()) + disks = "\n".join(partitions()) return ( - f'{user_name}@{host_name}\n---------\nOS: {os}\nUptime: {uptime}\n' - f'Motherboard: {mboard}\nCPU: {cpu}\nGPU: {gpu}\nMemory: {ram}\n' - f'Disk:\n{disks}' + f"{user_name}@{host_name}\n---------\nOS: {os}\nUptime: {uptime}\n" + f"Motherboard: {mboard}\nCPU: {cpu}\nGPU: {gpu}\nMemory: {ram}\n" + f"Disk:\n{disks}" ) diff --git a/pagermaid/modules/sudo.py b/pagermaid/modules/sudo.py index 39071a3..05b811f 100644 --- a/pagermaid/modules/sudo.py +++ b/pagermaid/modules/sudo.py @@ -1,8 +1,15 @@ from pagermaid.single_utils import sqlite from pagermaid.listener import listener -from pagermaid.group_manager import add_permission_for_group, Permission, remove_permission_for_group, \ - add_user_to_group, remove_user_from_group, add_permission_for_user, remove_permission_for_user, \ - permissions +from pagermaid.group_manager import ( + add_permission_for_group, + Permission, + remove_permission_for_group, + add_user_to_group, + remove_user_from_group, + add_permission_for_user, + remove_permission_for_user, + permissions, +) from pagermaid.enums import Client, Message from pagermaid.utils import lang, edit_delete, _status_sudo from pagermaid.single_utils import get_sudo_list @@ -15,17 +22,20 @@ def from_msg_get_sudo_id(message: Message) -> int: return message.chat.id -@listener(is_plugin=False, command="sudo", - need_admin=True, - parameters="{on|off|add|remove|gaddp|gaddu|gdelp|gdelu|glist|uaddp|udelp|list}", - description=lang('sudo_des')) +@listener( + is_plugin=False, + command="sudo", + need_admin=True, + parameters="{on|off|add|remove|gaddp|gaddu|gdelp|gdelu|glist|uaddp|udelp|list}", + description=lang("sudo_des"), +) async def sudo_change(client: Client, message: Message): - """ To enable or disable sudo of your userbot. """ + """To enable or disable sudo of your userbot.""" input_str = message.arguments sudo = get_sudo_list() if input_str == "on": if _status_sudo(): - return await edit_delete(message, lang('sudo_has_enabled')) + return await edit_delete(message, lang("sudo_has_enabled")) sqlite["sudo_enable"] = True text = f"__{lang('sudo_enable')}__\n" if len(sudo) != 0: @@ -48,7 +58,7 @@ async def sudo_change(client: Client, message: Message): return await message.edit( text, ) - await edit_delete(message, lang('sudo_has_disabled')) + await edit_delete(message, lang("sudo_has_disabled")) elif input_str == "add": from_id = from_msg_get_sudo_id(message) if from_id in sudo: @@ -85,7 +95,9 @@ async def sudo_change(client: Client, message: Message): for j in permissions.get_permissions_for_user(str(i)): text += f" • {'-' if j[2] == 'ejection' else ''}{j[1]}\n" except Exception: - text += f"• `{i}` - {' '.join(permissions.get_roles_for_user(str(i)))}\n" + text += ( + f"• `{i}` - {' '.join(permissions.get_roles_for_user(str(i)))}\n" + ) await message.edit(text) elif len(message.parameter) > 0: if len(message.parameter) == 2: @@ -113,20 +125,26 @@ async def sudo_change(client: Client, message: Message): add_permission_for_user(str(from_id), Permission(message.parameter[1])) return await message.edit(lang("sudo_user_add_per")) elif message.parameter[0] == "udelp": - remove_permission_for_user(str(from_id), Permission(message.parameter[1])) + remove_permission_for_user( + str(from_id), Permission(message.parameter[1]) + ) return await message.edit(lang("sudo_user_del_per")) else: - return await edit_delete(message, lang('arg_error')) + return await edit_delete(message, lang("arg_error")) if len(message.parameter) == 3: if message.parameter[0] == "gaddp": - add_permission_for_group(message.parameter[1], Permission(message.parameter[2])) + add_permission_for_group( + message.parameter[1], Permission(message.parameter[2]) + ) return await message.edit(lang("sudo_group_add_per")) elif message.parameter[0] == "gdelp": - remove_permission_for_group(message.parameter[1], Permission(message.parameter[2])) + remove_permission_for_group( + message.parameter[1], Permission(message.parameter[2]) + ) return await message.edit(lang("sudo_group_del_per")) else: - return await edit_delete(message, lang('arg_error')) + return await edit_delete(message, lang("arg_error")) else: - await edit_delete(message, lang('arg_error')) + await edit_delete(message, lang("arg_error")) else: - await edit_delete(message, lang('arg_error')) + await edit_delete(message, lang("arg_error")) diff --git a/pagermaid/modules/system.py b/pagermaid/modules/system.py index 7b21758..1d5b33e 100644 --- a/pagermaid/modules/system.py +++ b/pagermaid/modules/system.py @@ -11,24 +11,24 @@ from pagermaid.enums import Message from pagermaid.utils import attach_log, execute, lang, upload_attachment -@listener(is_plugin=False, command="sh", - need_admin=True, - description=lang('sh_des'), - parameters=lang('sh_parameters')) +@listener( + is_plugin=False, + command="sh", + need_admin=True, + description=lang("sh_des"), + parameters=lang("sh_parameters"), +) async def sh(message: Message): - """ Use the command-line from Telegram. """ + """Use the command-line from Telegram.""" user = getuser() command = message.arguments hostname = node() if not command: - await message.edit(lang('arg_error')) + await message.edit(lang("arg_error")) return - message = await message.edit( - f"`{user}`@{hostname} ~" - f"\n> `$` {command}" - ) + message = await message.edit(f"`{user}`@{hostname} ~" f"\n> `$` {command}") result = await execute(command) @@ -38,36 +38,37 @@ async def sh(message: Message): return await message.edit( - f"`{user}`@{hostname} ~" - f"\n> `#` {command}" - f"\n`{result}`" + f"`{user}`@{hostname} ~" f"\n> `#` {command}" f"\n`{result}`" ) else: return -@listener(is_plugin=False, command="restart", - need_admin=True, - description=lang('restart_des')) +@listener( + is_plugin=False, command="restart", need_admin=True, description=lang("restart_des") +) async def restart(message: Message): - """ To re-execute PagerMaid. """ + """To re-execute PagerMaid.""" if not message.text[0].isalpha(): - await message.edit(lang('restart_log')) + await message.edit(lang("restart_log")) exit(0) -@listener(is_plugin=False, command="eval", - need_admin=True, - description=lang('eval_des'), - parameters=lang('eval_parameters')) +@listener( + is_plugin=False, + command="eval", + need_admin=True, + description=lang("eval_des"), + parameters=lang("eval_parameters"), +) async def sh_eval(message: Message): - """ Run python commands from Telegram. """ + """Run python commands from Telegram.""" dev_mode = exists(f"data{sep}dev") try: assert dev_mode cmd = message.text.split(" ", maxsplit=1)[1] except (IndexError, AssertionError): - return await message.edit(lang('eval_need_dev')) + return await message.edit(lang("eval_need_dev")) final_output = await run_eval(cmd, message) if len(final_output) > 4096: message = await message.edit(f"**>>>** `{cmd}`", parse_mode=ParseMode.MARKDOWN) @@ -76,16 +77,21 @@ async def sh_eval(message: Message): await message.edit(final_output) -@listener(is_plugin=False, command="send_log", - need_admin=True, - description=lang("send_log_des")) +@listener( + is_plugin=False, + command="send_log", + need_admin=True, + description=lang("send_log_des"), +) async def send_log(message: Message): - """ Send log to a chat. """ + """Send log to a chat.""" if not exists("pagermaid.log.txt"): return await message.edit(lang("send_log_not_found")) - await upload_attachment("pagermaid.log.txt", - message.chat.id, - message.reply_to_message_id or message.reply_to_top_message_id, - thumb=f"pagermaid{sep}assets{sep}logo.jpg", - caption=lang("send_log_caption")) + await upload_attachment( + "pagermaid.log.txt", + message.chat.id, + message.reply_to_message_id or message.reply_to_top_message_id, + thumb=f"pagermaid{sep}assets{sep}logo.jpg", + caption=lang("send_log_caption"), + ) await message.safe_delete() diff --git a/pagermaid/modules/update.py b/pagermaid/modules/update.py index b0eaddc..2d3ee1f 100644 --- a/pagermaid/modules/update.py +++ b/pagermaid/modules/update.py @@ -5,11 +5,15 @@ from pagermaid.listener import listener from pagermaid.utils import lang, Message, alias_command -@listener(is_plugin=False, outgoing=True, command=alias_command("update"), - need_admin=True, - description=lang('update_des'), - parameters="") +@listener( + is_plugin=False, + outgoing=True, + command=alias_command("update"), + need_admin=True, + description=lang("update_des"), + parameters="", +) async def update(message: Message): await update_function(len(message.parameter) > 0) - await message.edit(lang('update_success')) + await message.edit(lang("update_success")) exit(0) diff --git a/pagermaid/modules/web.py b/pagermaid/modules/web.py index 7eaa6e8..5dcf344 100644 --- a/pagermaid/modules/web.py +++ b/pagermaid/modules/web.py @@ -14,5 +14,7 @@ async def init_web(): from pagermaid.web import app, init_web init_web() - server = uvicorn.Server(config=uvicorn.Config(app, host=Config.WEB_HOST, port=Config.WEB_PORT)) + server = uvicorn.Server( + config=uvicorn.Config(app, host=Config.WEB_HOST, port=Config.WEB_PORT) + ) bot.loop.create_task(server.serve()) diff --git a/pagermaid/scheduler.py b/pagermaid/scheduler.py index 81c2f61..8b99083 100644 --- a/pagermaid/scheduler.py +++ b/pagermaid/scheduler.py @@ -19,9 +19,12 @@ async def delete_message(message: Message) -> bool: def add_delete_message_job(message: Message, delete_seconds: int = 60): scheduler.add_job( - delete_message, "date", + delete_message, + "date", id=f"{message.chat.id}|{message.id}|delete_message", name=f"{message.chat.id}|{message.id}|delete_message", args=[message], - run_date=datetime.datetime.now(pytz.timezone(Config.TIME_ZONE)) + datetime.timedelta(seconds=delete_seconds), - replace_existing=True) + run_date=datetime.datetime.now(pytz.timezone(Config.TIME_ZONE)) + + datetime.timedelta(seconds=delete_seconds), + replace_existing=True, + ) diff --git a/pagermaid/services/__init__.py b/pagermaid/services/__init__.py index 40b39e9..35810b1 100644 --- a/pagermaid/services/__init__.py +++ b/pagermaid/services/__init__.py @@ -6,5 +6,11 @@ from pagermaid.utils import client def get(name: str): - data = {"Client": bot, "Logger": logs, "SqliteDict": sqlite, "AsyncIOScheduler": scheduler, "AsyncClient": client} + data = { + "Client": bot, + "Logger": logs, + "SqliteDict": sqlite, + "AsyncIOScheduler": scheduler, + "AsyncClient": client, + } return data.get(name, None) diff --git a/pagermaid/single_utils.py b/pagermaid/single_utils.py index 02dbdce..2d4d50d 100644 --- a/pagermaid/single_utils.py +++ b/pagermaid/single_utils.py @@ -9,7 +9,11 @@ from pyrogram import Client as OldClient from pyrogram.types import Chat as OldChat, Message as OldMessage, Dialog from pyromod.utils.conversation import Conversation -from pyromod.utils.errors import AlreadyInConversationError, TimeoutConversationError, ListenerCanceled +from pyromod.utils.errors import ( + AlreadyInConversationError, + TimeoutConversationError, + ListenerCanceled, +) from sqlitedict import SqliteDict @@ -39,49 +43,54 @@ class Message(OldMessage): chat: "Chat" def obtain_message(self) -> Optional[str]: - """ Obtains a message from either the reply message or command arguments. """ + """Obtains a message from either the reply message or command arguments.""" def obtain_user(self) -> Optional[int]: - """ Obtains a user from either the reply message or command arguments. """ + """Obtains a user from either the reply message or command arguments.""" async def delay_delete(self, delete_seconds: int = 60) -> Optional[bool]: - """ Deletes the message after a specified amount of seconds. """ + """Deletes the message after a specified amount of seconds.""" async def safe_delete(self, revoke: bool = True) -> None: - """ Safely deletes the message. """ + """Safely deletes the message.""" class Client(OldClient): job: Optional[AsyncIOScheduler] = None async def listen(self, chat_id, filters=None, timeout=None) -> Optional[Message]: - """ Listen for a message in a conversation. """ + """Listen for a message in a conversation.""" - async def ask(self, chat_id, text, filters=None, timeout=None, *args, **kwargs) -> Optional[Message]: - """ Ask a message in a conversation. """ + async def ask( + self, chat_id, text, filters=None, timeout=None, *args, **kwargs + ) -> Optional[Message]: + """Ask a message in a conversation.""" def cancel_listener(self, chat_id): - """ Cancel the conversation with the given chat_id. """ + """Cancel the conversation with the given chat_id.""" def cancel_all_listeners(self): - """ Cancel all conversations. """ + """Cancel all conversations.""" - def conversation(self, chat_id: Union[int, str], - once_timeout: int = 60, filters=None) -> Optional[Conversation]: - """ Initialize a conversation with the given chat_id. """ + def conversation( + self, chat_id: Union[int, str], once_timeout: int = 60, filters=None + ) -> Optional[Conversation]: + """Initialize a conversation with the given chat_id.""" async def get_dialogs_list(self) -> List[Dialog]: - """ Get a list of all dialogs. """ + """Get a list of all dialogs.""" class Chat(OldChat): is_forum: Optional[bool] = None async def listen(self, chat_id, filters=None, timeout=None) -> Optional[Message]: - """ Listen for a message in a conversation. """ + """Listen for a message in a conversation.""" - async def ask(self, chat_id, text, filters=None, timeout=None, *args, **kwargs) -> Optional[Message]: - """ Ask a message in a conversation. """ + async def ask( + self, chat_id, text, filters=None, timeout=None, *args, **kwargs + ) -> Optional[Message]: + """Ask a message in a conversation.""" def cancel_listener(self, chat_id): - """ Cancel the conversation with the given chat_id. """ + """Cancel the conversation with the given chat_id.""" diff --git a/pagermaid/utils.py b/pagermaid/utils.py index d9d545c..4dca63e 100644 --- a/pagermaid/utils.py +++ b/pagermaid/utils.py @@ -18,17 +18,17 @@ from pagermaid.single_utils import _status_sudo, get_sudo_list, Message, sqlite def lang(text: str) -> str: - """ i18n """ + """i18n""" return Config.lang_dict.get(text, text) def alias_command(command: str, disallow_alias: bool = False) -> str: - """ alias """ + """alias""" return command if disallow_alias else Config.alias_dict.get(command, command) async def attach_report(plaintext, file_name, reply_id=None, caption=None): - """ Attach plaintext as logs. """ + """Attach plaintext as logs.""" with open(file_name, "w+") as file: file.write(plaintext) try: @@ -36,7 +36,7 @@ async def attach_report(plaintext, file_name, reply_id=None, caption=None): "PagerMaid_Modify_bot", file_name, reply_to_message_id=reply_id, - caption=caption + caption=caption, ) except Exception: # noqa return @@ -44,20 +44,17 @@ async def attach_report(plaintext, file_name, reply_id=None, caption=None): async def attach_log(plaintext, chat_id, file_name, reply_id=None, caption=None): - """ Attach plaintext as logs. """ - with open(file_name, "w+", encoding='utf-8') as file: + """Attach plaintext as logs.""" + with open(file_name, "w+", encoding="utf-8") as file: file.write(plaintext) await bot.send_document( - chat_id, - file_name, - reply_to_message_id=reply_id, - caption=caption + chat_id, file_name, reply_to_message_id=reply_id, caption=caption ) remove(file_name) async def upload_attachment(file_path, chat_id, reply_id, caption=None, thumb=None): - """ Uploads a local attachment file. """ + """Uploads a local attachment file.""" if not exists(file_path): return False try: @@ -66,7 +63,7 @@ async def upload_attachment(file_path, chat_id, reply_id, caption=None, thumb=No file_path, thumb=thumb, reply_to_message_id=reply_id, - caption=caption + caption=caption, ) except BaseException as exception: raise exception @@ -74,32 +71,31 @@ async def upload_attachment(file_path, chat_id, reply_id, caption=None, thumb=No async def execute(command, pass_error=True): - """ Executes command and returns output, with the option of enabling stderr. """ + """Executes command and returns output, with the option of enabling stderr.""" executor = await create_subprocess_shell( - command, - stdout=PIPE, - stderr=PIPE, - stdin=PIPE + command, stdout=PIPE, stderr=PIPE, stdin=PIPE ) stdout, stderr = await executor.communicate() if pass_error: try: - result = str(stdout.decode().strip()) \ - + str(stderr.decode().strip()) + result = str(stdout.decode().strip()) + str(stderr.decode().strip()) except UnicodeDecodeError: - result = str(stdout.decode('gbk').strip()) \ - + str(stderr.decode('gbk').strip()) + result = str(stdout.decode("gbk").strip()) + str( + stderr.decode("gbk").strip() + ) else: try: result = str(stdout.decode().strip()) except UnicodeDecodeError: - result = str(stdout.decode('gbk').strip()) + result = str(stdout.decode("gbk").strip()) return result -def pip_install(package: str, version: Optional[str] = "", alias: Optional[str] = "") -> bool: - """ Auto install extra pypi packages """ +def pip_install( + package: str, version: Optional[str] = "", alias: Optional[str] = "" +) -> bool: + """Auto install extra pypi packages""" if not alias: # when import name is not provided, use package name alias = package @@ -110,32 +106,42 @@ def pip_install(package: str, version: Optional[str] = "", alias: Optional[str] return True -async def edit_delete(message: Message, - text: str, - time: int = 5, - parse_mode: Optional["enums.ParseMode"] = None, - disable_web_page_preview: bool = None): +async def edit_delete( + message: Message, + text: str, + time: int = 5, + parse_mode: Optional["enums.ParseMode"] = None, + disable_web_page_preview: bool = None, +): sudo_users = get_sudo_list() from_id = message.from_user.id if message.from_user else message.sender_chat.id if from_id in sudo_users: reply_to = message.reply_to_message event = ( - await reply_to.reply(text, disable_web_page_preview=disable_web_page_preview, parse_mode=parse_mode) + await reply_to.reply( + text, + disable_web_page_preview=disable_web_page_preview, + parse_mode=parse_mode, + ) if reply_to else await message.reply( - text, disable_web_page_preview=disable_web_page_preview, parse_mode=parse_mode + text, + disable_web_page_preview=disable_web_page_preview, + parse_mode=parse_mode, ) ) else: event = await message.edit( - text, disable_web_page_preview=disable_web_page_preview, parse_mode=parse_mode + text, + disable_web_page_preview=disable_web_page_preview, + parse_mode=parse_mode, ) await sleep(time) return await event.delete() def get_permission_name(is_plugin: bool, need_admin: bool, command: str) -> str: - """ Get permission name. """ + """Get permission name.""" if is_plugin: return f"plugins_root.{command}" if need_admin else f"plugins.{command}" else: @@ -147,7 +153,9 @@ def sudo_filter(permission: str): if not _status_sudo(): return False try: - from_id = message.from_user.id if message.from_user else message.sender_chat.id + from_id = ( + message.from_user.id if message.from_user else message.sender_chat.id + ) sudo_list = get_sudo_list() if from_id not in sudo_list: if message.chat.id in sudo_list: @@ -167,13 +175,15 @@ def from_self(message: Message) -> bool: def from_msg_get_sudo_uid(message: Message) -> int: - """ Get the sudo uid from the message. """ + """Get the sudo uid from the message.""" from_id = message.from_user.id if message.from_user else message.sender_chat.id return from_id if from_id in get_sudo_list() else message.chat.id def check_manage_subs(message: Message) -> bool: - return from_self(message) or enforce_permission(from_msg_get_sudo_uid(message), "modules.manage_subs") + return from_self(message) or enforce_permission( + from_msg_get_sudo_uid(message), "modules.manage_subs" + ) async def process_exit(start: int, _client, message=None): @@ -184,8 +194,13 @@ async def process_exit(start: int, _client, message=None): msg: Message = await _client.get_messages(cid, mid) if msg: await msg.edit( - ((msg.text or msg.caption) if msg.from_user.is_self and (msg.text or msg.caption) else "") + - f'\n\n> {lang("restart_complete")}') + ( + (msg.text or msg.caption) + if msg.from_user.is_self and (msg.text or msg.caption) + else "" + ) + + f'\n\n> {lang("restart_complete")}' + ) del sqlite["exit_msg"] if message: sqlite["exit_msg"] = {"cid": message.chat.id, "mid": message.id} diff --git a/pagermaid/web/__init__.py b/pagermaid/web/__init__.py index 935f68f..ed5f3c2 100644 --- a/pagermaid/web/__init__.py +++ b/pagermaid/web/__init__.py @@ -7,13 +7,13 @@ from pagermaid.config import Config from pagermaid.web.api import base_api_router from pagermaid.web.pages import admin_app, login_page -requestAdaptor = ''' +requestAdaptor = """ requestAdaptor(api) { api.headers["token"] = localStorage.getItem("token"); return api; }, -''' -responseAdaptor = ''' +""" +responseAdaptor = """ responseAdaptor(api, payload, query, request, response) { if (response.data.detail == '登录验证失败或已失效,请重新登录') { window.location.href = '/login' @@ -23,8 +23,8 @@ responseAdaptor(api, payload, query, request, response) { } return payload }, -''' -icon_path = 'https://xtaolabs.com/pagermaid-logo.png' +""" +icon_path = "https://xtaolabs.com/pagermaid-logo.png" app: FastAPI = FastAPI() @@ -36,25 +36,25 @@ def init_web(): allow_origins=Config.WEB_ORIGINS, allow_credentials=True, allow_methods=["*"], - allow_headers=["*"] + allow_headers=["*"], ) - @app.get('/', response_class=RedirectResponse) + @app.get("/", response_class=RedirectResponse) async def index(): - return '/admin' + return "/admin" - @app.get('/admin', response_class=HTMLResponse) + @app.get("/admin", response_class=HTMLResponse) async def admin(): return admin_app.render( - site_title='PagerMaid-Pyro 后台管理', + site_title="PagerMaid-Pyro 后台管理", site_icon=icon_path, requestAdaptor=requestAdaptor, - responseAdaptor=responseAdaptor + responseAdaptor=responseAdaptor, ) - @app.get('/login', response_class=HTMLResponse) + @app.get("/login", response_class=HTMLResponse) async def login(): return login_page.render( - site_title='登录 | PagerMaid-Pyro 后台管理', + site_title="登录 | PagerMaid-Pyro 后台管理", site_icon=icon_path, ) diff --git a/pagermaid/web/api/__init__.py b/pagermaid/web/api/__init__.py index 1168a39..46b3e99 100644 --- a/pagermaid/web/api/__init__.py +++ b/pagermaid/web/api/__init__.py @@ -8,7 +8,7 @@ from pagermaid.web.api.login import route as login_route from pagermaid.web.api.plugin import route as plugin_route from pagermaid.web.api.status import route as status_route -base_api_router = APIRouter(prefix='/pagermaid/api') +base_api_router = APIRouter(prefix="/pagermaid/api") base_api_router.include_router(plugin_route) base_api_router.include_router(bot_info_route) diff --git a/pagermaid/web/api/bot_info.py b/pagermaid/web/api/bot_info.py index b3c9231..99c4eca 100644 --- a/pagermaid/web/api/bot_info.py +++ b/pagermaid/web/api/bot_info.py @@ -10,16 +10,15 @@ from pagermaid.common.update import update route = APIRouter() -@route.post('/bot_update', response_class=JSONResponse, dependencies=[authentication()]) +@route.post("/bot_update", response_class=JSONResponse, dependencies=[authentication()]) async def bot_update(): await update() - return { - "status": 0, - "msg": "更新成功,请重启 PagerMaid-Pyro 以应用更新。" - } + return {"status": 0, "msg": "更新成功,请重启 PagerMaid-Pyro 以应用更新。"} -@route.post('/bot_restart', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/bot_restart", response_class=JSONResponse, dependencies=[authentication()] +) async def bot_restart(): os.kill(os.getpid(), signal.SIGINT) return {} diff --git a/pagermaid/web/api/command_alias.py b/pagermaid/web/api/command_alias.py index 6dd1e2f..e947d24 100644 --- a/pagermaid/web/api/command_alias.py +++ b/pagermaid/web/api/command_alias.py @@ -7,41 +7,41 @@ from pagermaid.web.api.utils import authentication route = APIRouter() -@route.get('/command_alias', response_class=JSONResponse, dependencies=[authentication()]) +@route.get( + "/command_alias", response_class=JSONResponse, dependencies=[authentication()] +) async def get_command_alias(): alias = AliasManager() return { - 'status': 0, - 'msg': 'ok', - 'data': { - 'items': alias.get_all_alias_dict(), - } + "status": 0, + "msg": "ok", + "data": { + "items": alias.get_all_alias_dict(), + }, } -@route.post('/command_alias', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/command_alias", response_class=JSONResponse, dependencies=[authentication()] +) async def add_command_alias(data: dict): - data = data['items'] + data = data["items"] try: await AliasManager.save_from_web(data) - return { - 'status': 0, - 'msg': '命令别名保存成功' - } + return {"status": 0, "msg": "命令别名保存成功"} except Exception: - return { - 'status': 1, - 'msg': '命令别名保存失败' - } + return {"status": 1, "msg": "命令别名保存失败"} -@route.get('/test_command_alias', response_class=JSONResponse, dependencies=[authentication()]) +@route.get( + "/test_command_alias", response_class=JSONResponse, dependencies=[authentication()] +) async def test_command_alias(message: str): alias = AliasManager() return { - 'status': 0, - 'msg': '测试成功', - 'data': { - 'new_msg': alias.test_alias(message), - } + "status": 0, + "msg": "测试成功", + "data": { + "new_msg": alias.test_alias(message), + }, } diff --git a/pagermaid/web/api/ignore_groups.py b/pagermaid/web/api/ignore_groups.py index 84df038..175a69e 100644 --- a/pagermaid/web/api/ignore_groups.py +++ b/pagermaid/web/api/ignore_groups.py @@ -7,39 +7,40 @@ from pagermaid.web.api import authentication route = APIRouter() -@route.get("/get_ignore_group_list", response_class=JSONResponse, dependencies=[authentication()]) +@route.get( + "/get_ignore_group_list", + response_class=JSONResponse, + dependencies=[authentication()], +) async def get_ignore_group_list(): try: groups = [] for data in await get_group_list(): data["status"] = ignore_groups_manager.check_id(data["id"]) groups.append(data) - return { - 'status': 0, - 'msg': 'ok', - 'data': { - 'groups': groups - } - } + return {"status": 0, "msg": "ok", "data": {"groups": groups}} except BaseException: - return { - 'status': -100, - 'msg': '获取群组列表失败' - } + return {"status": -100, "msg": "获取群组列表失败"} -@route.post('/set_ignore_group_status', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/set_ignore_group_status", + response_class=JSONResponse, + dependencies=[authentication()], +) async def set_ignore_group_status(data: dict): - cid: int = data.get('id') - status: bool = data.get('status') + cid: int = data.get("id") + status: bool = data.get("status") if status: ignore_groups_manager.add_id(cid) else: ignore_groups_manager.del_id(cid) - return {'status': 0, 'msg': f'成功{"忽略" if status else "取消忽略"} {cid}'} + return {"status": 0, "msg": f'成功{"忽略" if status else "取消忽略"} {cid}'} -@route.post('/clear_ignore_group', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/clear_ignore_group", response_class=JSONResponse, dependencies=[authentication()] +) async def clear_ignore_group(): ignore_groups_manager.clear_subs() - return {'status': 0, 'msg': '成功清空忽略列表'} + return {"status": 0, "msg": "成功清空忽略列表"} diff --git a/pagermaid/web/api/login.py b/pagermaid/web/api/login.py index 8b6827c..e9b5353 100644 --- a/pagermaid/web/api/login.py +++ b/pagermaid/web/api/login.py @@ -14,19 +14,13 @@ class UserModel(BaseModel): route = APIRouter() -@route.post('/login', response_class=JSONResponse) +@route.post("/login", response_class=JSONResponse) async def login(user: UserModel): if user.password != Config.WEB_SECRET_KEY: - return { - "status": -100, - "msg": "登录失败,请重新输入密钥" - } + return {"status": -100, "msg": "登录失败,请重新输入密钥"} token = create_token() return { "status": 0, - "msg": "登录成功", - "data": { - "version": pgm_version_code, - "token": token - } + "msg": "登录成功", + "data": {"version": pgm_version_code, "token": token}, } diff --git a/pagermaid/web/api/plugin.py b/pagermaid/web/api/plugin.py index 3b41d09..dd4e862 100644 --- a/pagermaid/web/api/plugin.py +++ b/pagermaid/web/api/plugin.py @@ -8,68 +8,68 @@ from pagermaid.web.api.utils import authentication route = APIRouter() -@route.get('/get_local_plugins', response_class=JSONResponse, dependencies=[authentication()]) +@route.get( + "/get_local_plugins", response_class=JSONResponse, dependencies=[authentication()] +) async def get_local_plugins(): plugins = [i.dict() for i in plugin_manager.plugins] - plugins.sort(key=lambda x: x['name']) - return { - 'status': 0, - 'msg': 'ok', - 'data': { - 'rows': plugins, - 'total': len(plugins) - } - } + plugins.sort(key=lambda x: x["name"]) + return {"status": 0, "msg": "ok", "data": {"rows": plugins, "total": len(plugins)}} -@route.post('/set_local_plugin_status', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/set_local_plugin_status", + response_class=JSONResponse, + dependencies=[authentication()], +) async def set_local_plugin_status(data: dict): - module_name: str = data.get('plugin') - status: bool = data.get('status') + module_name: str = data.get("plugin") + status: bool = data.get("status") if not (plugin := plugin_manager.get_local_plugin(module_name)): - return {'status': -100, 'msg': f'插件 {module_name} 不存在'} + return {"status": -100, "msg": f"插件 {module_name} 不存在"} if status: plugin.enable() else: plugin.disable() await reload_all() - return {'status': 0, 'msg': f'成功{"开启" if status else "关闭"} {module_name}'} + return {"status": 0, "msg": f'成功{"开启" if status else "关闭"} {module_name}'} -@route.post('/remove_local_plugin', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/remove_local_plugin", response_class=JSONResponse, dependencies=[authentication()] +) async def remove_local_plugin(data: dict): - module_name: str = data.get('plugin') + module_name: str = data.get("plugin") if not (plugin := plugin_manager.get_local_plugin(module_name)): - return {'status': -100, 'msg': f'插件 {module_name} 不存在'} + return {"status": -100, "msg": f"插件 {module_name} 不存在"} plugin_manager.remove_plugin(plugin.name) await reload_all() - return {'status': 0, 'msg': f'成功卸载 {module_name}'} + return {"status": 0, "msg": f"成功卸载 {module_name}"} -@route.get('/get_remote_plugins', response_class=JSONResponse, dependencies=[authentication()]) +@route.get( + "/get_remote_plugins", response_class=JSONResponse, dependencies=[authentication()] +) async def get_remote_plugins(): await plugin_manager.load_remote_plugins() plugins = [i.dict() for i in plugin_manager.remote_plugins] - plugins.sort(key=lambda x: x['name']) - return { - 'status': 0, - 'msg': 'ok', - 'data': { - 'rows': plugins, - 'total': len(plugins) - } - } + plugins.sort(key=lambda x: x["name"]) + return {"status": 0, "msg": "ok", "data": {"rows": plugins, "total": len(plugins)}} -@route.post('/set_remote_plugin_status', response_class=JSONResponse, dependencies=[authentication()]) +@route.post( + "/set_remote_plugin_status", + response_class=JSONResponse, + dependencies=[authentication()], +) async def set_remote_plugin_status(data: dict): - module_name: str = data.get('plugin') - status: bool = data.get('status') + module_name: str = data.get("plugin") + status: bool = data.get("status") if not plugin_manager.get_remote_plugin(module_name): - return {'status': 1, 'msg': f'插件 {module_name} 不存在'} + return {"status": 1, "msg": f"插件 {module_name} 不存在"} if status: await plugin_manager.install_remote_plugin(module_name) else: plugin_manager.remove_plugin(module_name) await reload_all() - return {'status': 0, 'msg': f'成功{"开启" if status else "关闭"} {module_name}'} + return {"status": 0, "msg": f'成功{"开启" if status else "关闭"} {module_name}'} diff --git a/pagermaid/web/api/status.py b/pagermaid/web/api/status.py index 8b9a928..f2ed888 100644 --- a/pagermaid/web/api/status.py +++ b/pagermaid/web/api/status.py @@ -13,7 +13,7 @@ from pagermaid.web.api.utils import authentication route = APIRouter() -@route.get('/log') +@route.get("/log") async def get_log(token: Optional[str] = Header(...), num: Union[int, str] = 100): if token != Config.WEB_SECRET_KEY: return "非法请求" @@ -31,8 +31,8 @@ async def get_log(token: Optional[str] = Header(...), num: Union[int, str] = 100 return StreamingResponse(streaming_logs()) -@route.get('/run_eval') -async def run_cmd(token: Optional[str] = Header(...), cmd: str = ''): +@route.get("/run_eval") +async def run_cmd(token: Optional[str] = Header(...), cmd: str = ""): if token != Config.WEB_SECRET_KEY: return "非法请求" @@ -45,8 +45,8 @@ async def run_cmd(token: Optional[str] = Header(...), cmd: str = ''): return StreamingResponse(run_cmd_func()) if cmd else "无效命令" -@route.get('/run_sh') -async def run_sh(token: Optional[str] = Header(...), cmd: str = ''): +@route.get("/run_sh") +async def run_sh(token: Optional[str] = Header(...), cmd: str = ""): if token != Config.WEB_SECRET_KEY: return "非法请求" @@ -59,6 +59,6 @@ async def run_sh(token: Optional[str] = Header(...), cmd: str = ''): return StreamingResponse(run_sh_func()) if cmd else "无效命令" -@route.get('/status', response_class=JSONResponse, dependencies=[authentication()]) +@route.get("/status", response_class=JSONResponse, dependencies=[authentication()]) async def status(): return (await get_status()).dict() diff --git a/pagermaid/web/api/utils.py b/pagermaid/web/api/utils.py index e3ee5d2..d44282d 100644 --- a/pagermaid/web/api/utils.py +++ b/pagermaid/web/api/utils.py @@ -6,7 +6,7 @@ from jose import jwt from pagermaid.config import Config -ALGORITHM = 'HS256' +ALGORITHM = "HS256" TOKEN_EXPIRE_MINUTES = 30 @@ -18,13 +18,14 @@ def authentication(): try: jwt.decode(token, Config.WEB_SECRET_KEY, algorithms=ALGORITHM) except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError): - raise HTTPException(status_code=400, detail='登录验证失败或已失效,请重新登录') + raise HTTPException(status_code=400, detail="登录验证失败或已失效,请重新登录") return Depends(inner) def create_token(): data = { - "exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=TOKEN_EXPIRE_MINUTES), + "exp": datetime.datetime.now(datetime.timezone.utc) + + datetime.timedelta(minutes=TOKEN_EXPIRE_MINUTES), } return jwt.encode(data, Config.WEB_SECRET_KEY, algorithm=ALGORITHM) diff --git a/pagermaid/web/html/__init__.py b/pagermaid/web/html/__init__.py index a513237..e770269 100644 --- a/pagermaid/web/html/__init__.py +++ b/pagermaid/web/html/__init__.py @@ -5,20 +5,20 @@ html_base_path = Path(__file__).parent def get_html(path: Path) -> str: """获取 HTML 模板。""" - with open(path, 'r', encoding='utf-8') as f: + with open(path, "r", encoding="utf-8") as f: return f.read() def get_logo() -> str: """获取 logo。""" - return get_html(html_base_path / 'logo.html') + return get_html(html_base_path / "logo.html") def get_github_logo() -> str: """获取 github logo。""" - return get_html(html_base_path / 'github_logo.html') + return get_html(html_base_path / "github_logo.html") def get_footer() -> str: """获取 footer。""" - return get_html(html_base_path / 'footer.html') + return get_html(html_base_path / "footer.html") diff --git a/pagermaid/web/pages/command_alias.py b/pagermaid/web/pages/command_alias.py index be9c868..edfffe2 100644 --- a/pagermaid/web/pages/command_alias.py +++ b/pagermaid/web/pages/command_alias.py @@ -1,50 +1,52 @@ from amis import Form, InputSubForm, InputText, Static, Alert, PageSchema, Page main_form = Form( - title='命令别名', - initApi='get:/pagermaid/api/command_alias', - api='post:/pagermaid/api/command_alias', - submitText='保存', + title="命令别名", + initApi="get:/pagermaid/api/command_alias", + api="post:/pagermaid/api/command_alias", + submitText="保存", body=[ InputSubForm( - name='items', - label='已设置的命令别名', + name="items", + label="已设置的命令别名", multiple=True, - btnLabel='${alias} >> ${command}', + btnLabel="${alias} >> ${command}", draggable=True, addable=True, removable=True, - addButtonText='添加命令别名', + addButtonText="添加命令别名", showErrorMsg=False, form=Form( - title='命令别名', + title="命令别名", body=[ - InputText(name='alias', label='命令别名', required=True), - InputText(name='command', label='原命令', required=True), - ] - ) + InputText(name="alias", label="命令别名", required=True), + InputText(name="command", label="原命令", required=True), + ], + ), ) - ] + ], ) test_form = Form( - title='测试', - api='get:/pagermaid/api/test_command_alias?message=${message}', - submitText='测试', + title="测试", + api="get:/pagermaid/api/test_command_alias?message=${message}", + submitText="测试", body=[ - InputText(name='message', label='测试消息(无需输入逗号前缀)', required=True), - Static(className='text-red-600', name='new_msg', label='命令别名修改后消息', - visibleOn="typeof data.new_msg !== 'undefined'") - ] + InputText(name="message", label="测试消息(无需输入逗号前缀)", required=True), + Static( + className="text-red-600", + name="new_msg", + label="命令别名修改后消息", + visibleOn="typeof data.new_msg !== 'undefined'", + ), + ], ) -tips = Alert(level='info') +tips = Alert(level="info") page = PageSchema( - url='/bot_config/command_alias', - icon='fa fa-link', label='命令别名', - schema=Page( - title='', - body=[tips, main_form, test_form] - ) + url="/bot_config/command_alias", + icon="fa fa-link", + label="命令别名", + schema=Page(title="", body=[tips, main_form, test_form]), ) diff --git a/pagermaid/web/pages/home_page.py b/pagermaid/web/pages/home_page.py index f7dacd2..84f2b17 100644 --- a/pagermaid/web/pages/home_page.py +++ b/pagermaid/web/pages/home_page.py @@ -1,49 +1,50 @@ -from amis import Page, PageSchema, Html, Property, Service, Flex, ActionType, LevelEnum, Divider, Log, Alert, Form, \ - Dialog, Select, Group, InputText, DisplayModeEnum, Horizontal +from amis import ( + Page, + PageSchema, + Html, + Property, + Service, + Flex, + ActionType, + LevelEnum, + Divider, + Log, + Alert, + Form, + Dialog, + Select, + Group, + InputText, + DisplayModeEnum, + Horizontal, +) from pagermaid.config import Config from pagermaid.web.html import get_logo logo = Html(html=get_logo()) select_log_num = Select( - label='日志数量', - name='log_num', + label="日志数量", + name="log_num", value=100, options=[ - { - 'label': 100, - 'value': 100 - }, - { - 'label': 200, - 'value': 200 - }, - { - 'label': 300, - 'value': 300 - }, - { - 'label': 400, - 'value': 400 - }, - { - 'label': 500, - 'value': 500 - } - ] + {"label": 100, "value": 100}, + {"label": 200, "value": 200}, + {"label": 300, "value": 300}, + {"label": 400, "value": 400}, + {"label": 500, "value": 500}, + ], ) log_page = Log( autoScroll=True, - placeholder='暂无日志数据...', - operation=['stop', 'showLineNumber', 'filter'], + placeholder="暂无日志数据...", + operation=["stop", "showLineNumber", "filter"], source={ - 'method': 'get', - 'url': '/pagermaid/api/log?num=${log_num | raw}', - 'headers': { - 'token': Config.WEB_SECRET_KEY - } - } + "method": "get", + "url": "/pagermaid/api/log?num=${log_num | raw}", + "headers": {"token": Config.WEB_SECRET_KEY}, + }, ) cmd_input = Form( @@ -51,132 +52,126 @@ cmd_input = Form( horizontal=Horizontal(left=0), wrapWithPanel=False, body=[ - InputText(name='command', required=True, clearable=True, addOn=ActionType.Dialog( - label='执行', - level=LevelEnum.primary, - dialog=Dialog( - title='命令执行结果', - size='xl', - body=Log( - autoScroll=True, - placeholder='执行命令中,请稍候...', - operation=['stop', 'showLineNumber', 'filter'], - source={ - 'method': 'get', - 'url': '/pagermaid/api/run_sh?cmd=${command | raw}', - 'headers': { - 'token': Config.WEB_SECRET_KEY - } - }), - ) - )) - ] + InputText( + name="command", + required=True, + clearable=True, + addOn=ActionType.Dialog( + label="执行", + level=LevelEnum.primary, + dialog=Dialog( + title="命令执行结果", + size="xl", + body=Log( + autoScroll=True, + placeholder="执行命令中,请稍候...", + operation=["stop", "showLineNumber", "filter"], + source={ + "method": "get", + "url": "/pagermaid/api/run_sh?cmd=${command | raw}", + "headers": {"token": Config.WEB_SECRET_KEY}, + }, + ), + ), + ), + ) + ], ) eval_input = Form( mode=DisplayModeEnum.horizontal, horizontal=Horizontal(left=0), wrapWithPanel=False, body=[ - InputText(name='command', required=True, clearable=True, addOn=ActionType.Dialog( - label='执行', + InputText( + name="command", + required=True, + clearable=True, + addOn=ActionType.Dialog( + label="执行", + level=LevelEnum.primary, + dialog=Dialog( + title="命令执行结果", + size="xl", + body=Log( + autoScroll=True, + placeholder="执行命令中,请稍候...", + operation=["stop", "showLineNumber", "filter"], + source={ + "method": "get", + "url": "/pagermaid/api/run_eval?cmd=${command | raw}", + "headers": {"token": Config.WEB_SECRET_KEY}, + }, + ), + ), + ), + ) + ], +) + +operation_button = Flex( + justify="center", + items=[ + ActionType.Ajax( + label="更新", + api="/pagermaid/api/bot_update", + confirmText="该操作会更新 PagerMaid-Pyro ,请在更新完成后手动重启,请确认执行该操作", + level=LevelEnum.info, + ), + ActionType.Ajax( + label="重启", + className="m-l", + api="/pagermaid/api/bot_restart", + confirmText="该操作会重启 PagerMaid-Pyro ,请耐心等待重启", + level=LevelEnum.danger, + ), + ActionType.Dialog( + label="日志", + className="m-l", level=LevelEnum.primary, dialog=Dialog( - title='命令执行结果', - size='xl', - body=Log( - autoScroll=True, - placeholder='执行命令中,请稍候...', - operation=['stop', 'showLineNumber', 'filter'], - source={ - 'method': 'get', - 'url': '/pagermaid/api/run_eval?cmd=${command | raw}', - 'headers': { - 'token': Config.WEB_SECRET_KEY - } - }), - ) - )) - ] + title="查看日志", + size="xl", + actions=[], + body=[ + Alert( + level=LevelEnum.info, + body='查看最近最多500条日志,不会自动刷新,需要手动点击两次"暂停键"来进行刷新。', + ), + Form(body=[Group(body=[select_log_num]), log_page]), + ], + ), + ), + ActionType.Dialog( + label="shell", + className="m-l", + level=LevelEnum.warning, + dialog=Dialog(title="shell", size="lg", actions=[], body=[cmd_input]), + ), + ActionType.Dialog( + label="eval", + className="m-l", + level=LevelEnum.warning, + dialog=Dialog(title="eval", size="lg", actions=[], body=[eval_input]), + ), + ], ) -operation_button = Flex(justify='center', items=[ - ActionType.Ajax( - label='更新', - api='/pagermaid/api/bot_update', - confirmText='该操作会更新 PagerMaid-Pyro ,请在更新完成后手动重启,请确认执行该操作', - level=LevelEnum.info - ), - ActionType.Ajax( - label='重启', - className='m-l', - api='/pagermaid/api/bot_restart', - confirmText='该操作会重启 PagerMaid-Pyro ,请耐心等待重启', - level=LevelEnum.danger - ), - ActionType.Dialog( - label='日志', - className='m-l', - level=LevelEnum.primary, - dialog=Dialog(title='查看日志', - size='xl', - actions=[], - body=[ - Alert(level=LevelEnum.info, - body='查看最近最多500条日志,不会自动刷新,需要手动点击两次"暂停键"来进行刷新。'), - Form( - body=[Group(body=[select_log_num]), log_page] - )]) - ), - ActionType.Dialog( - label='shell', - className='m-l', - level=LevelEnum.warning, - dialog=Dialog(title='shell', - size='lg', - actions=[], - body=[cmd_input]) - ), - ActionType.Dialog( - label='eval', - className='m-l', - level=LevelEnum.warning, - dialog=Dialog(title='eval', - size='lg', - actions=[], - body=[eval_input]) - ) -]) - status = Service( - api='/pagermaid/api/status', + api="/pagermaid/api/status", body=Property( - title='运行信息', + title="运行信息", column=2, items=[ - Property.Item( - label='Bot 版本', - content='${version}' - ), - Property.Item( - label='Bot 运行时间', - content='${run_time}' - ), - Property.Item( - label='CPU占用率', - content='${cpu_percent}' - ), - Property.Item( - label='RAM占用率', - content='${ram_percent}' - ), - Property.Item( - label='SWAP占用率', - content='${swap_percent}', - span=2 - ), - ] - ) + Property.Item(label="Bot 版本", content="${version}"), + Property.Item(label="Bot 运行时间", content="${run_time}"), + Property.Item(label="CPU占用率", content="${cpu_percent}"), + Property.Item(label="RAM占用率", content="${ram_percent}"), + Property.Item(label="SWAP占用率", content="${swap_percent}", span=2), + ], + ), ) -page_detail = Page(title='', body=[logo, operation_button, Divider(), status]) -page = PageSchema(url='/home', label='首页', icon='fa fa-home', isDefaultPage=True, schema=page_detail) +page_detail = Page(title="", body=[logo, operation_button, Divider(), status]) +page = PageSchema( + url="/home", label="首页", icon="fa fa-home", isDefaultPage=True, schema=page_detail +) diff --git a/pagermaid/web/pages/ignore_groups.py b/pagermaid/web/pages/ignore_groups.py index d2fbfd4..6b39021 100644 --- a/pagermaid/web/pages/ignore_groups.py +++ b/pagermaid/web/pages/ignore_groups.py @@ -1,63 +1,71 @@ -from amis import InputText, Switch, Card, Tpl, CardsCRUD, PageSchema, Page, Button, Select +from amis import ( + InputText, + Switch, + Card, + Tpl, + CardsCRUD, + PageSchema, + Page, + Button, + Select, +) card = Card( header=Card.Header( - title='$title', - description='$id', - avatarText='$title', - avatarTextClassName='overflow-hidden' + title="$title", + description="$id", + avatarText="$title", + avatarTextClassName="overflow-hidden", ), actions=[], toolbar=[ Switch( - name='enable', - value='${status}', - onText='已忽略', - offText='未忽略', + name="enable", + value="${status}", + onText="已忽略", + offText="未忽略", onEvent={ - 'change': { - 'actions': { - 'actionType': 'ajax', - 'args': { - 'api': { - 'url': '/pagermaid/api/set_ignore_group_status', - 'method': 'post' + "change": { + "actions": { + "actionType": "ajax", + "args": { + "api": { + "url": "/pagermaid/api/set_ignore_group_status", + "method": "post", }, - 'messages': { - 'success': '成功${IF(event.data.value, "忽略", "取消忽略")}了 ${title}', - 'failed': '操作失败' + "messages": { + "success": '成功${IF(event.data.value, "忽略", "取消忽略")}了 ${title}', + "failed": "操作失败", }, - 'status': '${event.data.value}', - 'id': '${id}' - } + "status": "${event.data.value}", + "id": "${id}", + }, } } - } + }, ) - ] + ], ) cards_curd = CardsCRUD( - mode='cards', - title='', + mode="cards", + title="", syncLocation=False, - api='/pagermaid/api/get_ignore_group_list', + api="/pagermaid/api/get_ignore_group_list", loadDataOnce=True, - source='${groups | filter:title:match:keywords_name}', - filter={ - 'body': [ - InputText(name='keywords_name', label='群组名') - ] - }, + source="${groups | filter:title:match:keywords_name}", + filter={"body": [InputText(name="keywords_name", label="群组名")]}, perPage=12, autoJumpToTopOnPagerChange=True, - placeholder='群组列表为空', - footerToolbar=['switch-per-page', 'pagination'], + placeholder="群组列表为空", + footerToolbar=["switch-per-page", "pagination"], columnsCount=3, - card=card + card=card, ) page = PageSchema( - url='/bot_config/ignore_groups', - icon='fa fa-ban', - label='忽略群组', - schema=Page(title='忽略群组', subTitle="忽略后,Bot 不再响应指定群组的消息(群组列表将会缓存一小时)", body=cards_curd) + url="/bot_config/ignore_groups", + icon="fa fa-ban", + label="忽略群组", + schema=Page( + title="忽略群组", subTitle="忽略后,Bot 不再响应指定群组的消息(群组列表将会缓存一小时)", body=cards_curd + ), ) diff --git a/pagermaid/web/pages/login.py b/pagermaid/web/pages/login.py index 857d5dd..f19a374 100644 --- a/pagermaid/web/pages/login.py +++ b/pagermaid/web/pages/login.py @@ -1,32 +1,42 @@ -from amis import Form, InputPassword, DisplayModeEnum, Horizontal, Remark, Html, Page, AmisAPI, Wrapper +from amis import ( + Form, + InputPassword, + DisplayModeEnum, + Horizontal, + Remark, + Html, + Page, + AmisAPI, + Wrapper, +) from pagermaid.web.html import get_logo logo = Html(html=get_logo()) login_api = AmisAPI( - url='/pagermaid/api/login', - method='post', - adaptor=''' + url="/pagermaid/api/login", + method="post", + adaptor=""" if (payload.status == 0) { localStorage.setItem("token", payload.data.token); } return payload; - ''' + """, ) login_form = Form( api=login_api, - title='', + title="", body=[ InputPassword( - name='password', - label='密码', - labelRemark=Remark(shape='circle', content='登录密码') + name="password", + label="密码", + labelRemark=Remark(shape="circle", content="登录密码"), ), ], mode=DisplayModeEnum.horizontal, horizontal=Horizontal(left=3, right=9, offset=5), - redirect='/admin', + redirect="/admin", ) -body = Wrapper(className='w-2/5 mx-auto my-0 m:w-full', body=login_form) -login_page = Page(title='', body=[logo, body]) +body = Wrapper(className="w-2/5 mx-auto my-0 m:w-full", body=login_form) +login_page = Page(title="", body=[logo, body]) diff --git a/pagermaid/web/pages/main.py b/pagermaid/web/pages/main.py index 1adf313..c39b4ff 100644 --- a/pagermaid/web/pages/main.py +++ b/pagermaid/web/pages/main.py @@ -8,25 +8,33 @@ from pagermaid.web.pages.plugin_local_manage import page as plugin_local_manage_ from pagermaid.web.pages.plugin_remote_manage import page as plugin_remote_manage_page github_logo = Tpl( - className='w-full', + className="w-full", tpl=get_github_logo(), ) -header = Flex(className='w-full', justify='flex-end', alignItems='flex-end', items=[github_logo]) +header = Flex( + className="w-full", justify="flex-end", alignItems="flex-end", items=[github_logo] +) admin_app = App( - brandName='pagermaid', - logo='https://xtaolabs.com/pagermaid-logo.png', + brandName="pagermaid", + logo="https://xtaolabs.com/pagermaid-logo.png", header=header, pages=[ { - 'children': [ + "children": [ home_page, - PageSchema(label='Bot 设置', icon='fa fa-wrench', - children=[command_alias_page, ignore_groups_page]), - PageSchema(label='插件管理', icon='fa fa-cube', - children=[plugin_local_manage_page, plugin_remote_manage_page]), + PageSchema( + label="Bot 设置", + icon="fa fa-wrench", + children=[command_alias_page, ignore_groups_page], + ), + PageSchema( + label="插件管理", + icon="fa fa-cube", + children=[plugin_local_manage_page, plugin_remote_manage_page], + ), ] } ], footer=get_footer(), ) -blank_page = Page(title='PagerMaid-Pyro 404', body='404') +blank_page = Page(title="PagerMaid-Pyro 404", body="404") diff --git a/pagermaid/web/pages/plugin_local_manage.py b/pagermaid/web/pages/plugin_local_manage.py index aabbe5a..e15b0f1 100644 --- a/pagermaid/web/pages/plugin_local_manage.py +++ b/pagermaid/web/pages/plugin_local_manage.py @@ -2,63 +2,57 @@ from amis import InputText, Switch, Card, CardsCRUD, PageSchema, Page card = Card( header=Card.Header( - title='$name', - avatarText='$name', - avatarTextClassName='overflow-hidden' + title="$name", avatarText="$name", avatarTextClassName="overflow-hidden" ), actions=[], toolbar=[ Switch( - name='enable', - value='${status}', - onText='启用', - offText='禁用', + name="enable", + value="${status}", + onText="启用", + offText="禁用", onEvent={ - 'change': { - 'actions': [ + "change": { + "actions": [ { - 'actionType': 'ajax', - 'args': { - 'api': { - 'url': '/pagermaid/api/set_local_plugin_status', - 'method': 'post' + "actionType": "ajax", + "args": { + "api": { + "url": "/pagermaid/api/set_local_plugin_status", + "method": "post", }, - 'messages': { - 'success': '成功${IF(event.data.value, "开启", "禁用")}了 ${name}', - 'failed': '操作失败' + "messages": { + "success": '成功${IF(event.data.value, "开启", "禁用")}了 ${name}', + "failed": "操作失败", }, - 'status': '${event.data.value}', - 'plugin': '${name}' - } + "status": "${event.data.value}", + "plugin": "${name}", + }, }, ] } - } + }, ) - ] + ], ) cards_curd = CardsCRUD( - mode='cards', - title='', + mode="cards", + title="", syncLocation=False, - api='/pagermaid/api/get_local_plugins', + api="/pagermaid/api/get_local_plugins", loadDataOnce=True, - source='${rows | filter:name:match:keywords_name}', - filter={ - 'body': [ - InputText(name='keywords_name', label='插件名') - ] - }, + source="${rows | filter:name:match:keywords_name}", + filter={"body": [InputText(name="keywords_name", label="插件名")]}, perPage=12, autoJumpToTopOnPagerChange=True, - placeholder='暂无插件信息', - footerToolbar=['switch-per-page', 'pagination'], + placeholder="暂无插件信息", + footerToolbar=["switch-per-page", "pagination"], columnsCount=3, - card=card + card=card, ) page = PageSchema( - url='/plugins/local', - icon='fa fa-database', - label='本地插件管理', - schema=Page(title='本地插件管理', body=cards_curd) + url="/plugins/local", + icon="fa fa-database", + label="本地插件管理", + schema=Page(title="本地插件管理", body=cards_curd), ) diff --git a/pagermaid/web/pages/plugin_remote_manage.py b/pagermaid/web/pages/plugin_remote_manage.py index c702744..91618dc 100644 --- a/pagermaid/web/pages/plugin_remote_manage.py +++ b/pagermaid/web/pages/plugin_remote_manage.py @@ -2,63 +2,63 @@ from amis import InputText, Switch, Card, Tpl, CardsCRUD, PageSchema, Page, Butt card = Card( header=Card.Header( - title='$name', - description='$des', - avatarText='$name', - avatarTextClassName='overflow-hidden' + title="$name", + description="$des", + avatarText="$name", + avatarTextClassName="overflow-hidden", ), actions=[], toolbar=[ Switch( - name='enable', - value='${status}', - onText='已安装', - offText='未安装', + name="enable", + value="${status}", + onText="已安装", + offText="未安装", onEvent={ - 'change': { - 'actions': { - 'actionType': 'ajax', - 'args': { - 'api': { - 'url': '/pagermaid/api/set_remote_plugin_status', - 'method': 'post' + "change": { + "actions": { + "actionType": "ajax", + "args": { + "api": { + "url": "/pagermaid/api/set_remote_plugin_status", + "method": "post", }, - 'messages': { - 'success': '成功${IF(event.data.value, "安装", "卸载")}了 ${name}', - 'failed': '操作失败' + "messages": { + "success": '成功${IF(event.data.value, "安装", "卸载")}了 ${name}', + "failed": "操作失败", }, - 'status': '${event.data.value}', - 'plugin': '${name}' - } + "status": "${event.data.value}", + "plugin": "${name}", + }, } } - } + }, ) - ] + ], ) cards_curd = CardsCRUD( - mode='cards', - title='', + mode="cards", + title="", syncLocation=False, - api='/pagermaid/api/get_remote_plugins', + api="/pagermaid/api/get_remote_plugins", loadDataOnce=True, - source='${rows | filter:name:match:keywords_name | filter:des:match:keywords_description}', + source="${rows | filter:name:match:keywords_name | filter:des:match:keywords_description}", filter={ - 'body': [ - InputText(name='keywords_name', label='插件名'), - InputText(name='keywords_description', label='插件描述') + "body": [ + InputText(name="keywords_name", label="插件名"), + InputText(name="keywords_description", label="插件描述"), ] }, perPage=12, autoJumpToTopOnPagerChange=True, - placeholder='暂无插件信息', - footerToolbar=['switch-per-page', 'pagination'], + placeholder="暂无插件信息", + footerToolbar=["switch-per-page", "pagination"], columnsCount=3, - card=card + card=card, ) page = PageSchema( - url='/plugins/remote', - icon='fa fa-cloud-download', - label='插件仓库', - schema=Page(title='插件仓库', body=cards_curd) + url="/plugins/remote", + icon="fa fa-cloud-download", + label="插件仓库", + schema=Page(title="插件仓库", body=cards_curd), ) diff --git a/pyromod/filters/filters.py b/pyromod/filters/filters.py index bae411d..c52d680 100644 --- a/pyromod/filters/filters.py +++ b/pyromod/filters/filters.py @@ -22,7 +22,7 @@ import pyrogram def dice(ctx, message): - return hasattr(message, 'dice') and message.dice + return hasattr(message, "dice") and message.dice pyrogram.filters.dice = dice diff --git a/pyromod/listen/listen.py b/pyromod/listen/listen.py index 8f41e70..2e49b05 100644 --- a/pyromod/listen/listen.py +++ b/pyromod/listen/listen.py @@ -54,12 +54,8 @@ class Client: chat_id = chat.id future = self.loop.create_future() - future.add_done_callback( - functools.partial(self.clear_listener, chat_id) - ) - self.listening.update({ - chat_id: {"future": future, "filters": filters} - }) + future.add_done_callback(functools.partial(self.clear_listener, chat_id)) + self.listening.update({chat_id: {"future": future, "filters": filters}}) try: return await asyncio.wait_for(future, timeout) except asyncio.exceptions.TimeoutError as e: @@ -81,11 +77,11 @@ class Client: @patchable def cancel_listener(self, chat_id): listener = self.listening.get(chat_id) - if not listener or listener['future'].done(): + if not listener or listener["future"].done(): return - listener['future'].set_exception(ListenerCanceled()) - self.clear_listener(chat_id, listener['future']) + listener["future"].set_exception(ListenerCanceled()) + self.clear_listener(chat_id, listener["future"]) @patchable def cancel_all_listener(self): @@ -93,25 +89,25 @@ class Client: self.cancel_listener(chat_id) @patchable - def conversation(self, chat_id: Union[int, str], once_timeout: int = 60, filters=None): + def conversation( + self, chat_id: Union[int, str], once_timeout: int = 60, filters=None + ): return Conversation(self, chat_id, once_timeout, filters) @patchable async def read_chat_history( - self: "pyrogram.Client", - chat_id: Union[int, str], - max_id: int = 0 + self: "pyrogram.Client", chat_id: Union[int, str], max_id: int = 0 ) -> bool: peer = await self.resolve_peer(chat_id) if isinstance(peer, pyrogram.raw.types.InputPeerChannel): - with contextlib.suppress(pyrogram.errors.BadRequest): # noqa + with contextlib.suppress(pyrogram.errors.BadRequest): # noqa topics: pyrogram.raw.types.messages.ForumTopics = await self.invoke( pyrogram.raw.functions.channels.GetForumTopics( - channel=peer, # noqa + channel=peer, # noqa offset_date=0, offset_id=0, offset_topic=0, - limit=0 + limit=0, ) ) for i in topics.topics: @@ -139,25 +135,25 @@ class MessageHandler: @patchable async def resolve_listener(self, client, message, *args): listener = client.listening.get(message.chat.id) - if listener and not listener['future'].done(): - listener['future'].set_result(message) + if listener and not listener["future"].done(): + listener["future"].set_result(message) else: - if listener and listener['future'].done(): - client.clear_listener(message.chat.id, listener['future']) + if listener and listener["future"].done(): + client.clear_listener(message.chat.id, listener["future"]) await self.user_callback(client, message, *args) @patchable async def check(self, client, update): listener = client.listening.get(update.chat.id) - if listener and not listener['future'].done(): - return await listener['filters'](client, update) if callable(listener['filters']) else True + if listener and not listener["future"].done(): + return ( + await listener["filters"](client, update) + if callable(listener["filters"]) + else True + ) - return ( - await self.filters(client, update) - if callable(self.filters) - else True - ) + return await self.filters(client, update) if callable(self.filters) else True @patch(pyrogram.handlers.edited_message_handler.EditedMessageHandler) @@ -170,25 +166,25 @@ class EditedMessageHandler: @patchable async def resolve_listener(self, client, message, *args): listener = client.listening.get(message.chat.id) - if listener and not listener['future'].done(): - listener['future'].set_result(message) + if listener and not listener["future"].done(): + listener["future"].set_result(message) else: - if listener and listener['future'].done(): - client.clear_listener(message.chat.id, listener['future']) + if listener and listener["future"].done(): + client.clear_listener(message.chat.id, listener["future"]) await self.user_callback(client, message, *args) @patchable async def check(self, client, update): listener = client.listening.get(update.chat.id) - if listener and not listener['future'].done(): - return await listener['filters'](client, update) if callable(listener['filters']) else True + if listener and not listener["future"].done(): + return ( + await listener["filters"](client, update) + if callable(listener["filters"]) + else True + ) - return ( - await self.filters(client, update) - if callable(self.filters) - else True - ) + return await self.filters(client, update) if callable(self.filters) else True @patch(pyrogram.types.user_and_chats.chat.Chat) @@ -208,21 +204,27 @@ class Chat(pyrogram.types.Chat): @patchable @staticmethod def _parse_user_chat(client, user: pyrogram.raw.types.User) -> "Chat": - chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_user_chat(client, user) # noqa + chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_user_chat( + client, user + ) # noqa chat.is_forum = None return chat @patchable @staticmethod def _parse_chat_chat(client, chat: pyrogram.raw.types.Chat) -> "Chat": - chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_chat_chat(client, chat) # noqa + chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_chat_chat( + client, chat + ) # noqa chat.is_forum = None return chat @patchable @staticmethod def _parse_channel_chat(client, channel: pyrogram.raw.types.Channel) -> "Chat": - chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_channel_chat(client, channel) # noqa + chat = pyrogram.types.user_and_chats.chat.Chat.old_parse_channel_chat( + client, channel + ) # noqa chat.is_forum = getattr(channel, "forum", None) return chat @@ -251,23 +253,21 @@ class Message(pyrogram.types.Message): async def safe_delete(self, revoke: bool = True): try: return await self._client.delete_messages( - chat_id=self.chat.id, - message_ids=self.id, - revoke=revoke + chat_id=self.chat.id, message_ids=self.id, revoke=revoke ) except Exception: # noqa return False @patchable def obtain_message(self) -> Optional[str]: - """ Obtains a message from either the reply message or command arguments. """ + """Obtains a message from either the reply message or command arguments.""" return self.arguments or ( self.reply_to_message.text if self.reply_to_message else None ) @patchable def obtain_user(self) -> Optional[int]: - """ Obtains a user from either the reply message or command arguments. """ + """Obtains a user from either the reply message or command arguments.""" user = None # Priority: reply > argument > current_chat if self.reply_to_message: # Reply to a user @@ -279,9 +279,14 @@ class Message(pyrogram.types.Message): if raw_user.isnumeric(): user = int(raw_user) elif self.entities is not None: - if self.entities[0].type == pyrogram.enums.MessageEntityType.TEXT_MENTION: + if ( + self.entities[0].type + == pyrogram.enums.MessageEntityType.TEXT_MENTION + ): user = self.entities[0].user.id - if not user and self.chat.type == pyrogram.enums.ChatType.PRIVATE: # Current chat + if ( + not user and self.chat.type == pyrogram.enums.ChatType.PRIVATE + ): # Current chat user = self.chat.id return user @@ -291,13 +296,13 @@ class Message(pyrogram.types.Message): @patchable async def edit_text( - self, - text: str, - parse_mode: Optional["pyrogram.enums.ParseMode"] = None, - entities: List["pyrogram.types.MessageEntity"] = None, - disable_web_page_preview: bool = None, - reply_markup: "pyrogram.types.InlineKeyboardMarkup" = None, - no_reply: bool = None, + self, + text: str, + parse_mode: Optional["pyrogram.enums.ParseMode"] = None, + entities: List["pyrogram.types.MessageEntity"] = None, + disable_web_page_preview: bool = None, + reply_markup: "pyrogram.types.InlineKeyboardMarkup" = None, + no_reply: bool = None, ) -> "Message": msg = None sudo_users = get_sudo_list() @@ -317,7 +322,7 @@ class Message(pyrogram.types.Message): text=text, parse_mode=parse_mode, disable_web_page_preview=disable_web_page_preview, - quote=True + quote=True, ) elif is_self: msg = await self._client.edit_message_text( @@ -327,14 +332,14 @@ class Message(pyrogram.types.Message): parse_mode=parse_mode, entities=entities, disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup + reply_markup=reply_markup, ) elif not no_reply: msg = await self.reply( text=text, parse_mode=parse_mode, disable_web_page_preview=disable_web_page_preview, - quote=True + quote=True, ) else: try: @@ -345,9 +350,11 @@ class Message(pyrogram.types.Message): parse_mode=parse_mode, entities=entities, disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup + reply_markup=reply_markup, ) - except pyrogram.errors.exceptions.forbidden_403.MessageAuthorRequired: # noqa + except ( + pyrogram.errors.exceptions.forbidden_403.MessageAuthorRequired + ): # noqa if not no_reply: msg = await self.reply( text=text, @@ -355,15 +362,13 @@ class Message(pyrogram.types.Message): entities=entities, disable_web_page_preview=disable_web_page_preview, reply_markup=reply_markup, - quote=True + quote=True, ) else: with open("output.log", "w+") as file: file.write(text) msg = await self._client.send_document( - chat_id=self.chat.id, - document="output.log", - reply_to_message_id=self.id + chat_id=self.chat.id, document="output.log", reply_to_message_id=self.id ) if not msg: return self @@ -381,9 +386,11 @@ class Message(pyrogram.types.Message): users: dict, chats: dict, is_scheduled: bool = False, - replies: int = 1 + replies: int = 1, ): - parsed = await pyrogram.types.Message.old_parse(client, message, users, chats, is_scheduled, replies) # noqa + parsed = await pyrogram.types.Message.old_parse( + client, message, users, chats, is_scheduled, replies + ) # noqa # forum topic if isinstance(message, pyrogram.raw.types.Message): parsed.forum_topic = getattr(message.reply_to, "forum_topic", None) @@ -414,8 +421,8 @@ class Message(pyrogram.types.Message): "pyrogram.types.InlineKeyboardMarkup", "pyrogram.types.ReplyKeyboardMarkup", "pyrogram.types.ReplyKeyboardRemove", - "pyrogram.types.ForceReply" - ] = object + "pyrogram.types.ForceReply", + ] = object, ) -> Union["pyrogram.types.Message", List["pyrogram.types.Message"]]: if self.media: self.text = None diff --git a/pyromod/methods/sign_in_qrcode.py b/pyromod/methods/sign_in_qrcode.py index 2b44842..e83016f 100644 --- a/pyromod/methods/sign_in_qrcode.py +++ b/pyromod/methods/sign_in_qrcode.py @@ -30,14 +30,20 @@ async def sign_in_qrcode( await client.session.stop() await client.storage.dc_id(req.dc_id) await client.storage.auth_key( - await Auth(client, await client.storage.dc_id(), await client.storage.test_mode()).create() + await Auth( + client, await client.storage.dc_id(), await client.storage.test_mode() + ).create() ) client.session = Session( - client, await client.storage.dc_id(), - await client.storage.auth_key(), await client.storage.test_mode() + client, + await client.storage.dc_id(), + await client.storage.auth_key(), + await client.storage.test_mode(), ) await client.session.start() - req = await client.invoke(pyrogram.raw.functions.auth.ImportLoginToken(token=req.token)) + req = await client.invoke( + pyrogram.raw.functions.auth.ImportLoginToken(token=req.token) + ) await client.storage.user_id(req.authorization.user.id) await client.storage.is_bot(False) return pyrogram.types.User._parse(client, req.authorization.user) @@ -51,8 +57,10 @@ async def authorize_by_qrcode( client: Client, ): print(f"Welcome to Pyrogram (version {pyrogram.__version__})") - print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n" - f"under the terms of the {pyrogram.__license__}.\n") + print( + f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n" + f"under the terms of the {pyrogram.__license__}.\n" + ) while True: qrcode = None @@ -66,7 +74,9 @@ async def authorize_by_qrcode( print(f"Password hint: {await client.get_password_hint()}") if not client.password: - client.password = await ainput("Enter password (empty to recover): ", hide=client.hide_password) + client.password = await ainput( + "Enter password (empty to recover): ", hide=client.hide_password + ) try: if client.password: @@ -96,8 +106,12 @@ async def authorize_by_qrcode( except Exception: print("Save qrcode.png failed.") print(qr_obj.terminal()) - print(f"Scan the QR code above, the qrcode.png file or visit {qrcode} to log in.\n") - print("QR code will expire in 20 seconds. If you have scanned it, please wait...") + print( + f"Scan the QR code above, the qrcode.png file or visit {qrcode} to log in.\n" + ) + print( + "QR code will expire in 20 seconds. If you have scanned it, please wait..." + ) await asyncio.sleep(20) elif isinstance(qrcode, pyrogram.types.User): return qrcode @@ -114,7 +128,9 @@ async def start_client(client: Client): await client.authorize() if not await client.storage.is_bot() and client.takeout: - client.takeout_id = (await client.invoke(pyrogram.raw.functions.account.InitTakeoutSession())).id + client.takeout_id = ( + await client.invoke(pyrogram.raw.functions.account.InitTakeoutSession()) + ).id await client.invoke(pyrogram.raw.functions.updates.GetState()) except (Exception, KeyboardInterrupt): diff --git a/pyromod/utils/conversation.py b/pyromod/utils/conversation.py index f2f3101..25dac53 100644 --- a/pyromod/utils/conversation.py +++ b/pyromod/utils/conversation.py @@ -12,12 +12,14 @@ def _checks_cancelled(f): raise asyncio.CancelledError("The conversation was cancelled before") return f(self, *args, **kwargs) + return wrapper class Conversation: - def __init__(self, client, chat_id: Union[int, str], - once_timeout: int = 60, filters=None): + def __init__( + self, client, chat_id: Union[int, str], once_timeout: int = 60, filters=None + ): self._client = client self._chat_id = chat_id self._once_timeout = once_timeout @@ -56,7 +58,9 @@ class Conversation: async def ask(self, text, filters=None, timeout=None, *args, **kwargs): filters = filters or self._filters timeout = timeout or self._once_timeout - return await self._client.ask(self._chat_id, text, filters=filters, timeout=timeout, *args, **kwargs) + return await self._client.ask( + self._chat_id, text, filters=filters, timeout=timeout, *args, **kwargs + ) @_checks_cancelled async def get_response(self, filters=None, timeout=None): @@ -65,7 +69,9 @@ class Conversation: return await self._client.listen(self._chat_id, filters, timeout) def mark_as_read(self, message=None): - return self._client.read_chat_history(self._chat_id, max_id=message.id if message else 0) + return self._client.read_chat_history( + self._chat_id, max_id=message.id if message else 0 + ) def cancel(self): self._cancelled = True diff --git a/pyromod/utils/errors.py b/pyromod/utils/errors.py index b6dd849..0ec0450 100644 --- a/pyromod/utils/errors.py +++ b/pyromod/utils/errors.py @@ -2,6 +2,7 @@ class AlreadyInConversationError(Exception): """ Occurs when another exclusive conversation is opened in the same chat. """ + def __init__(self): super().__init__( "Cannot open exclusive conversation in a " @@ -13,10 +14,9 @@ class TimeoutConversationError(Exception): """ Occurs when the conversation times out. """ + def __init__(self): - super().__init__( - "Response read timed out" - ) + super().__init__("Response read timed out") class ListenerCanceled(Exception): @@ -25,6 +25,4 @@ class ListenerCanceled(Exception): """ def __init__(self): - super().__init__( - "Listener was canceled" - ) + super().__init__("Listener was canceled") diff --git a/pyromod/utils/utils.py b/pyromod/utils/utils.py index cb9edc3..2202260 100644 --- a/pyromod/utils/utils.py +++ b/pyromod/utils/utils.py @@ -21,12 +21,12 @@ along with pyromod. If not, see . def patch(obj): def is_patchable(item): - return getattr(item[1], 'patchable', False) + return getattr(item[1], "patchable", False) def wrapper(container): for name, func in filter(is_patchable, container.__dict__.items()): old = getattr(obj, name, None) - setattr(obj, f'old{name}', old) + setattr(obj, f"old{name}", old) setattr(obj, name, func) return container diff --git a/requirements.txt b/requirements.txt index d12c6a3..846a22a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pyrogram==2.0.100 +pyrogram==2.0.101 TgCrypto==1.2.5 Pillow>=8.4.0 pytz>=2021.3 @@ -6,15 +6,15 @@ PyYAML>=6.0 coloredlogs>=15.0.1 psutil>=5.8.0 httpx~=0.23.3 -apscheduler==3.10.0 +apscheduler>=3.10.1 sqlitedict~=2.1.0 -casbin==1.17.6 +casbin==1.18.0 sentry-sdk==1.16.0 PyQRCode>=1.2.1 PyPng -fastapi==0.92.0 +fastapi==0.94.0 amis-python==1.0.7 python-jose uvicorn -pydantic==1.10.5 -starlette==0.25.0 +pydantic==1.10.6 +starlette==0.26.0.post1 diff --git a/utils/gensession.py b/utils/gensession.py index 1196ff6..e38363e 100644 --- a/utils/gensession.py +++ b/utils/gensession.py @@ -5,6 +5,7 @@ from sys import executable, exit try: from pyrogram.errors import ApiIdInvalid, PhoneNumberInvalid from pyrogram import Client + print("Found an existing installation of Pyrogram...\nSuccessfully Imported.") except ImportError: print("Installing Pyrogram...") @@ -32,10 +33,14 @@ async def main(): "me", f"**PagerMaid** `String SESSION`:\n\n`{await bot.export_session_string()}`", ) - print("Your SESSION has been generated. Check your telegram saved messages!") + print( + "Your SESSION has been generated. Check your telegram saved messages!" + ) exit(0) except ApiIdInvalid: - print("Your API ID/API HASH combination is invalid. Kindly recheck.\nQuitting...") + print( + "Your API ID/API HASH combination is invalid. Kindly recheck.\nQuitting..." + ) exit(0) except ValueError: print("API HASH must not be empty!\nQuitting...")