async def on_add_plugin_u(c, u): is_query = hasattr(u, "data") if is_query: await u.message.delete() lang = u._lang loop_count = 0 while True: loop_count += 1 if not is_query and u.document: msg = u if loop_count > 1: break # avoid infinite loop elif not is_query and u.reply_to_message and u.reply_to_message.document: msg = u.reply_to_message if loop_count > 1: break # avoid infinite loop else: msg = await u.from_user.ask(lang.plugin_file_ask) if await filters.regex("/cancel")(c, msg): return await msg.reply(lang.command_cancelled) if not msg.document: await msg.reply(lang.plugin_waiting_file, quote=True) continue if not re.search("(py)$", msg.document.file_name): await msg.reply(lang.plugin_format_not_accepted, quote=True) continue if msg.document.file_size > (5 * 1024 * 1024): await msg.reply(lang.plugin_too_big, quote=True) continue break filename = await msg.download(f"cache/") filename = os.path.relpath(filename) plugin = read_plugin_info(filename) # Showing info text = write_plugin_info(plugins, lang, plugin, status_line="") lines = [ [ (lang.add, f"confirm_add_plugin {plugin['type']} {filename}"), (lang.cancel, "cancel_plugin"), ] ] keyb = ikb(lines) await msg.reply(text, keyb, disable_web_page_preview=True, quote=True)
async def on_plugin_action(c, m): lang = m._lang action = m.matches[0]["action"] if action in ["+", "add"]: if await filters.me(c, m): await m.delete() return await on_add_plugin_u(c, m) # remove plugin on .plugin rm act = m.edit if await filters.me(c, m) else m.reply msg = m.reply_to_message if not msg.document: return await act(lang.plugin_rm_not_document) if not msg.document.file_name.endswith(".py"): return await act(lang.plugin_rm_not_py) basename = msg.document.file_name cache_filename = await msg.download("cache/") plugin = read_plugin_info(cache_filename) if not plugin: os.remove(cache_filename) return await msg.reply(lang.plugin_info_block_not_found, quote=True) plugin_type = plugin["type"] if basename not in plugins[plugin_type]: return await act(lang.plugin_rm_not_added(name=basename)) plugin = plugins[plugin_type][basename] # compare files via hash with open(cache_filename) as remote_file, open( plugin["filename"]) as local_file: local_data = local_file.read() local_hash = hashlib.md5(local_data.encode()).hexdigest()[:10] temp_data = remote_file.read() remote_hash = hashlib.md5(temp_data.encode()).hexdigest()[:10] os.remove(cache_filename) if local_hash != remote_hash: return await act(lang.plugin_rm_remote_local_are_diff(name=basename)) inactive = await get_inactive_plugins(plugins) if not os.path.exists(plugin["filename"]): del plugins[plugin_type][basename] return await act(lang.plugin_not_exists_on_server) if plugin["notation"] in inactive: inactive = [x for x in inactive if x != plugin["notation"]] await Config.get(key="INACTIVE_PLUGINS" ).update(value=json.dumps(inactive)) try: module = importlib.import_module(plugin["notation"]) except Exception as e: os.remove(plugin["filename"]) return await act(lang.plugin_could_not_load(e=e)) functions = [*filter(callable, module.__dict__.values())] functions = [*filter(lambda f: hasattr(f, "handler"), functions)] client = (user, bot)[plugin_type == "bot"] for f in functions: client.remove_handler(*f.handler) del plugins[plugin_type][basename] os.remove(plugin["filename"]) await act(lang.plugin_removed_text(name=basename))
workdir=".", config_file="./config.ini", **pyrogram_config, ) bot.set_parse_mode("html") cmds = [ "help", "ping", "upgrade", "restart", "eval", "exec", "cmd", "settings", "plugins", "commands", "start", ] cmds = {x: 1 for x in cmds} plugins = {"user": {}, "bot": {}} for file in glob.glob("userlixo/handlers/*/plugins/*.py"): basename = os.path.basename(file) plugin_type = ("user", "bot")["handlers/bot/" in file] if basename.startswith("__"): continue info = read_plugin_info(file) plugins[plugin_type][basename] = info
async def on_confirm_plugin(c, cq): lang = cq._lang module = None plugin_type = cq.matches[0]["plugin_type"] client = (user, bot)[plugin_type == "bot"] cache_filename = cq.matches[0]["filename"] basename = os.path.basename(cache_filename) new_filename = "userlixo/handlers/" + plugin_type + "/plugins/" + basename plugin = read_plugin_info(cache_filename) new_notation = re.sub("\.py$", "", os.path.relpath(new_filename)).replace("/", ".") requirements = plugin.get("requirements") if requirements: DGRAY = 'echo -e "\033[1;30m"' RESET = 'echo -e "\033[0m"' req_list = requirements.split() req_text = "" for r in req_list[:-1]: req_text += f" ├ <code>{r}</code>\n" req_text += f" └ <code>{req_list[-1]}</code>" text = lang.installing_plugin_requirements text.escape_html = False await cq.edit(text(requirements=req_text)) os.system(f"{DGRAY}; {sys.executable} -m pip install {requirements}; {RESET}") # Safely unload the plugin if existent if os.path.exists(new_filename): try: module = importlib.import_module(new_notation) except Exception as e: return await cq.edit( lang.plugin_could_not_load_existent(name=basename, e=e) ) functions = [*filter(callable, module.__dict__.values())] functions = [*filter(lambda f: hasattr(f, "handlers"), functions)] for f in functions: for handler in f.handlers: client.remove_handler(*handler) os.renames(cache_filename, new_filename) plugin = read_plugin_info(new_filename) try: if module: importlib.reload(module) module = importlib.import_module(plugin["notation"]) except Exception as e: os.remove(new_filename) await cq.edit(lang.plugin_could_not_load(e=e)) raise e functions = [*filter(callable, module.__dict__.values())] functions = [*filter(lambda f: hasattr(f, "handlers"), functions)] if not len(functions): os.remove(new_filename) return await cq.edit(lang.plugin_has_no_handlers) for f in functions: for handler in f.handlers: client.add_handler(*handler) plugins[plugin_type][basename] = plugin reload_plugins_requirements(plugins) inactive = await get_inactive_plugins(plugins) if plugin["notation"] in inactive: inactive = [x for x in inactive if x != plugin["notation"]] await Config.get(key="INACTIVE_PLUGINS").update(value=json.dumps(inactive)) # Discover which page is this plugin listed in quant_per_page = 4 * 2 # lines times columns page = math.ceil(len(plugins) / quant_per_page) keyb = ikb( [[(lang.see_plugin_info, f"info_plugin {basename} {plugin_type} {page}")]] ) text = lang.plugin_added(name=basename) if "DYNO" in os.environ: text += "\n\n" + lang.alert_need_deploy await cq.edit(text, keyb)