🔖 Update to v1.1.0

This commit is contained in:
xtaodada 2022-06-20 21:55:14 +08:00
parent ba9da97b3c
commit 2a1b54802b
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
28 changed files with 545 additions and 355 deletions

View File

@ -245,14 +245,14 @@ coin_lost: I lost my coin
## lang
lang_des: Switch language.
lang_change_to: The language has been switched to
lang_reboot: Restarting.
lang_reboot: Reloading.
lang_current_lang: The current language is
lang_all_lang: All available languages are
## alias
alias_des: Redirect original command.
alias_list: 'The following is a list of redirect commands:'
alias_no: You have not redirected any original commands.
alias_success: Edit redirection command successPagerMaid-Pyro is restarting.
alias_success: Edit redirection command successPagerMaid-Pyro is reloading.
alias_exist: Something went wrong, woooo~ The command that is redirected is already occupied.
alias_no_exist: Something went wrong, woooo~ The original command is not redirected.
#message
@ -309,7 +309,7 @@ apt_processing: Installing plugins...
apt_no_py: Something went wrong ~ Failed to get the plug-in file from the attachment.
apt_plugin: plugin
apt_installed: installed
apt_reboot: PagerMaid-Pyro is restarting.
apt_reboot: PagerMaid-Pyro is reloading.
apt_install_success: successful installation
apt_not_found: not founded
apt_no_update: no need to update
@ -553,3 +553,6 @@ sb_remove: The automatic banned list has been removed this group.
sb_exist: This group exists in the automatic banned list.
sb_no_exist: This group does't exist in the automatic banned list.
sb_channel: Successfully blocked this channel in this group.
#reload
reload_des: Reload the PagerMaid-Pyro instance.
reload_ok: Successfully reloaded.

View File

@ -245,14 +245,14 @@ coin_lost: I lost my coin
## lang
lang_des: switchlanguage.
lang_change_to: The language has been switchedto
lang_reboot: Restarting.
lang_reboot: リロード中
lang_current_lang: 拡張カードの pubage is
lang_all_lang: All available languages are
## alias
alias_des: Redirect original command。
alias_list: 'The following is a list of redirect commands:'
alias_no: You have not redirected any original commands.
alias_success: Edit redirection command success,PagerMaid-Pyro is restarting.
alias_success: リダイレクトコマンドの編集に成功しました。PagerMaid-Pyro がリロードされています。
alias_exist: Something went wrong, woo~ The commd that is redirected is already occupied。
alias_no_exist: Something went wrong, woo~ The original commd is not redirected.
#message
@ -309,7 +309,7 @@ apt_processing: Installing plugins...
apt_no_py: Something went wrong ~ Failed to get the plug-in file from the attachment.
apt_plugin: plugin
apt_installed: installed
apt_reboot: PagerMaid-Pyro is restarting
apt_reboot: PagerMaid-Pyroはリロードされています
apt_install_success: successful installation
apt_not_found: not founded
apt_no_update: no need to update
@ -553,3 +553,6 @@ sb_remove: The automatic banned list has been removed this group.
sb_exist: This group exists in the automatic banned list.
sb_no_exist: This group does't exist in the automatic banned list.
sb_channel: Successfully blocked this channel in this group.
#reload
reload_des: PagerMaid-Pyroインスタンスをリロードします。
reload_ok: 再読み込みに成功しました。

View File

@ -245,14 +245,14 @@ coin_lost: 我丢了硬币
## lang
lang_des: 切换语言。
lang_change_to: 语言已切换到
lang_reboot: 正在重新启动
lang_reboot: 正在重新加载
lang_current_lang: 当前语言是
lang_all_lang: 所有可用的语言有:
## alias
alias_des: 重定向原始命令。
alias_list: '以下是重定向命令列表:'
alias_no: 您还没有重定向任何原始命令。
alias_success: 编辑重定向命令成功PagerMaid-Pyro 正在重新启动
alias_success: 编辑重定向命令成功PagerMaid-Pyro 正在重新加载
alias_exist: 出错了呜呜呜 ~ 重定向指向的命令已被占用。
alias_no_exist: 出错了呜呜呜 ~ 原始命令没有被重定向。
#message
@ -309,7 +309,7 @@ apt_processing: 安装插件中 . . .
apt_no_py: 出错了呜呜呜 ~ 无法从附件获取插件文件。
apt_plugin: 插件
apt_installed: 已安装
apt_reboot: PagerMaid-Pyro 正在重新启动
apt_reboot: PagerMaid-Pyro 正在重新加载中
apt_install_success: 安装成功
apt_not_found: 没有找到
apt_no_update: 无需更新
@ -553,3 +553,6 @@ sb_remove: 已被移除自动封禁列表。
sb_exist: 此群组存在于自动封禁列表中。
sb_no_exist: 此群组不存在于自动封禁列表中。
sb_channel: 成功在本群封禁此频道。
#reload
reload_des: 重新加载内置模块和插件。
reload_ok: 重新加载内置模块和插件成功。

View File

@ -245,14 +245,14 @@ coin_lost: 我擲了硬幣
## lang
lang_des: 切換語言
lang_change_to: 語言已切換到
lang_reboot: 正在重新啟動
lang_reboot: 正在重新加載
lang_current_lang: 目前語言是
lang_all_lang: 所有語言有這些:
## alias
alias_des: 重定向原始命令。
alias_list: '以下是重定向命令列表:'
alias_no: 您還沒有重定向任何原始命令。
alias_success: 編輯重定向命令成功PagerMaid-Pyro 正在重新啟動
alias_success: 編輯重定向命令成功PagerMaid-Pyro 正在重新加载
alias_exist: 出錯了嗚嗚嗚 ~ 重定向指向的命令已被佔用。
alias_no_exist: 出錯了嗚嗚嗚 ~ 原始命令沒有被重定向。
#message
@ -309,7 +309,7 @@ apt_processing: 安裝插件中…
apt_no_py: Error無法獲取插件文件。
apt_plugin: 插件
apt_installed: 已安裝
apt_reboot: 正在重新啟動 PagerMaid-Pyro。
apt_reboot: PagerMaid-Pyro 正在重新加載
apt_install_success: 安裝成功
apt_not_found: Error沒有找到插件
apt_no_update: 沒必要更新
@ -553,3 +553,6 @@ sb_remove: 已被移除自動封禁列表。
sb_exist: 此群組存在於自動封禁列表中。
sb_no_exist: 此群組不存在於自動封禁列表中。
sb_channel: 成功在本群封禁此頻道。
#reload
reload_des: 重新加載內置模塊和插件。
reload_ok: 重新加載內置模塊和插件成功。

View File

@ -1,15 +1,16 @@
import contextlib
from coloredlogs import ColoredFormatter
from datetime import datetime, timezone
from logging import getLogger, StreamHandler, CRITICAL, INFO, basicConfig, DEBUG
from datetime import datetime
from os import getcwd
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from pagermaid.config import Config
from pagermaid.scheduler import scheduler
import pyromod.listen
from pyrogram import Client
import sys
pgm_version = "1.0.9"
pgm_version = "1.1.0"
CMD_LIST = {}
module_dir = __path__[0]
working_dir = getcwd()
@ -17,9 +18,7 @@ working_dir = getcwd()
read_context = {}
help_messages = {}
all_permissions = []
scheduler = AsyncIOScheduler(timezone="Asia/ShangHai")
if not scheduler.running:
scheduler.start()
logs = getLogger(__name__)
logging_format = "%(levelname)s [%(asctime)s] [%(name)s] %(message)s"
logging_handler = StreamHandler()
@ -27,6 +26,9 @@ logging_handler.setFormatter(ColoredFormatter(logging_format))
root_logger = getLogger()
root_logger.setLevel(DEBUG if Config.DEBUG else CRITICAL)
root_logger.addHandler(logging_handler)
pyro_logger = getLogger("pyrogram")
pyro_logger.setLevel(CRITICAL)
pyro_logger.addHandler(logging_handler)
basicConfig(level=DEBUG if Config.DEBUG else INFO)
logs.setLevel(DEBUG if Config.DEBUG else INFO)
@ -38,19 +40,21 @@ elif not Config.API_HASH:
logs.error("Api-Hash Not Found!")
sys.exit(1)
start_time = datetime.utcnow()
start_time = datetime.now(timezone.utc)
try:
import uvloop
with contextlib.suppress(ImportError):
import uvloop # noqa
uvloop.install()
except ImportError:
pass
if not scheduler.running:
scheduler.start()
bot = Client("pagermaid",
session_string=Config.STRING_SESSION,
api_id=Config.API_ID,
api_hash=Config.API_HASH,
ipv6=Config.IPV6,
proxy=Config.PROXY)
bot.job = scheduler
async def log(message):

View File

@ -18,12 +18,12 @@ async def main():
for module_name in module_list:
try:
import_module("pagermaid.modules." + module_name)
import_module(f"pagermaid.modules.{module_name}")
except BaseException as exception:
logs.info(f"{lang('module')} {module_name} {lang('error')}: {type(exception)}: {exception}")
for plugin_name in plugin_list:
try:
import_module("plugins." + plugin_name)
import_module(f"plugins.{plugin_name}")
except BaseException as exception:
logs.info(f"{lang('module')} {plugin_name} {lang('error')}: {exception}")
plugin_list.remove(plugin_name)

View File

@ -17,7 +17,7 @@ class Permission:
self.name = name[1:] if name.startswith("-") else name
self.root = self.name.split(".")[0]
self.sub = self.name.split(".")[1] if len(self.name.split(".")) > 1 else ""
self.enable: bool = False if name.startswith("-") else True
self.enable: bool = not name.startswith("-")
self.act: str = "access" if self.enable else "ejection"
@ -25,12 +25,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"):
if not permissions.enforce(str(user), permission, "ejection"):
return True
if permissions.enforce(str(user), permission, "access"):
if not permissions.enforce(str(user), permission, "ejection"):
return True
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
@ -43,7 +45,7 @@ def parse_pen(pen: Permission) -> List[Permission]:
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:
datas.append(i)
if len(datas) == 0:
if not datas:
raise ValueError("No permission found")
return datas
@ -61,40 +63,28 @@ def remove_user_from_group(user: str, group: str):
def add_permission_for_group(group: str, permission: Permission):
if "*" in permission.name:
data = parse_pen(permission)
else:
data = [permission]
data = parse_pen(permission) if "*" in permission.name else [permission]
for i in data:
permissions.add_policy(group, i.name, permission.act, "allow")
permissions.save_policy()
def remove_permission_for_group(group: str, permission: Permission):
if "*" in permission.name:
data = parse_pen(permission)
else:
data = [permission]
data = parse_pen(permission) if "*" in permission.name else [permission]
for i in data:
permissions.remove_policy(group, i.name, permission.act, "allow")
permissions.save_policy()
def add_permission_for_user(user: str, permission: Permission):
if "*" in permission.name:
data = parse_pen(permission)
else:
data = [permission]
data = parse_pen(permission) if "*" in permission.name else [permission]
for i in data:
permissions.add_permission_for_user(user, i.name, permission.act, "allow")
permissions.save_policy()
def remove_permission_for_user(user: str, permission: Permission):
if "*" in permission.name:
data = parse_pen(permission)
else:
data = [permission]
data = parse_pen(permission) if "*" in permission.name else [permission]
for i in data:
permissions.delete_permission_for_user(user, i.name, permission.act, "allow")
permissions.save_policy()

View File

@ -1,3 +1,4 @@
import contextlib
import sys
import secrets
from asyncio import sleep
@ -5,7 +6,6 @@ from time import strftime, gmtime, time
from traceback import format_exc
from pyrogram import ContinuePropagation, StopPropagation, filters, Client
from pagermaid.single_utils import Message
from pyrogram.errors.exceptions.bad_request_400 import (
MessageIdInvalid,
MessageNotModified,
@ -16,7 +16,9 @@ from pyrogram.handlers import MessageHandler, EditedMessageHandler
from pagermaid import help_messages, logs, Config, bot, read_context, all_permissions
from pagermaid.group_manager import Permission
from pagermaid.single_utils import Message
from pagermaid.utils import lang, attach_report, sudo_filter, alias_command, get_permission_name, process_exit
from pagermaid.utils import client as httpx_client
secret_generator = secrets.SystemRandom()
@ -97,7 +99,8 @@ def listener(**args):
def decorator(function):
async def handler(client: Client, message: Message):
message.client = client
message.bot = client
message.request = httpx_client
try:
try:
@ -116,11 +119,14 @@ def listener(**args):
raise ContinuePropagation
read_context[(message.chat.id, message.id)] = True
await function(client, message)
except StopPropagation:
raise StopPropagation
except KeyboardInterrupt:
raise KeyboardInterrupt
if function.__code__.co_argcount == 1:
await function(message)
elif function.__code__.co_argcount == 2:
await function(client, message)
except StopPropagation as e:
raise StopPropagation from e
except KeyboardInterrupt as e:
raise KeyboardInterrupt from e
except MessageNotModified:
pass
except MessageIdInvalid:
@ -129,29 +135,21 @@ def listener(**args):
)
except UserNotParticipant:
pass
except ContinuePropagation:
raise ContinuePropagation
except ContinuePropagation as e:
raise ContinuePropagation from e
except SystemExit:
await process_exit(start=False, _client=client, message=message)
sys.exit(0)
except BaseException:
exc_info = sys.exc_info()[1]
exc_format = format_exc()
try:
with contextlib.suppress(BaseException):
await message.edit(lang("run_error"), no_reply=True) # noqa
except BaseException:
pass
if not diagnostics:
return
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 if message.text else message.caption}\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"
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()}.pagermaid", None,
"Error report generated.")
if (message.chat.id, message.id) in read_context:
@ -185,12 +183,18 @@ def raw_listener(filter_s):
def decorator(function):
async def handler(client, message):
message.bot = client
message.request = httpx_client
try:
await function(client, message)
except StopPropagation:
raise StopPropagation
except ContinuePropagation:
raise ContinuePropagation
if function.__code__.co_argcount == 1:
await function(message)
elif function.__code__.co_argcount == 2:
await function(client, message)
except StopPropagation as e:
raise StopPropagation from e
except ContinuePropagation as e:
raise ContinuePropagation from e
except SystemExit:
await process_exit(start=False, _client=client, message=message)
sys.exit(0)
@ -201,10 +205,8 @@ def raw_listener(filter_s):
except BaseException:
exc_info = sys.exc_info()[1]
exc_format = format_exc()
try:
with contextlib.suppress(BaseException):
await message.edit(lang('run_error'), no_reply=True)
except BaseException:
pass
if Config.ERROR_REPORT:
report = f"# Generated: {strftime('%H:%M %d/%m/%Y', gmtime())}. \n" \
f"# ChatID: {message.chat.id}. \n" \

View File

@ -8,37 +8,38 @@ from pagermaid.utils import lang
def __list_modules():
module_paths = glob(dirname(__file__) + f"{sep}*.py")
result = [
module_paths = glob(f"{dirname(__file__)}{sep}*.py")
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")
]
return result
def __list_plugins():
plugin_paths = glob(f"{getcwd()}{sep}plugins" + f"{sep}*.py")
if not exists(f"{getcwd()}{sep}plugins"):
makedirs(f"{getcwd()}{sep}plugins")
result = [
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")
]
return result
module_list_string = ""
plugin_list_string = ""
for module in sorted(__list_modules()):
module_list_string += f"{module}, "
module_list_string = "".join(
f"{module}, " for module in sorted(__list_modules())
)
module_list_string = module_list_string[:-2]
for plugin in sorted(__list_plugins()):
plugin_list_string += f"{plugin}, "
plugin_list_string = "".join(
f"{plugin}, " for plugin in sorted(__list_plugins())
)
plugin_list_string = plugin_list_string[:-2]

View File

@ -1,6 +1,5 @@
from os import remove
from pyrogram import Client
from pyrogram.errors import UsernameNotOccupied, PeerIdInvalid
from pyrogram.types import User
@ -8,11 +7,13 @@ from pagermaid import Config
from pagermaid.listener import listener
from pagermaid.utils import lang, Message
import contextlib
@listener(is_plugin=False, outgoing=True, command="profile",
@listener(is_plugin=False, command="profile",
description=lang('profile_des'),
parameters="<username>")
async def profile(client: Client, message: Message):
async def profile(message: Message):
""" Queries profile of a user. """
if len(message.parameter) > 1:
await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
@ -29,7 +30,7 @@ async def profile(client: Client, message: Message):
if user.isdigit():
user = int(user)
else:
user = await client.get_me()
user = await message.bot.get_me()
if message.entities is not None:
if message.entities[0].type == "text_mention":
user = message.entities[0].user
@ -39,7 +40,7 @@ async def profile(client: Client, message: Message):
return await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
if not isinstance(user, User):
try:
user = await client.get_users(user)
user = await message.bot.get_users(user)
except PeerIdInvalid:
return await message.edit(f"{lang('error_prefix')}{lang('profile_e_nof')}")
except UsernameNotOccupied:
@ -66,10 +67,10 @@ async def profile(client: Client, message: Message):
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)
photo = await message.bot.download_media(user.photo.big_file_id)
reply_to = message.reply_to_message
try:
await client.send_photo(
await message.bot.send_photo(
message.chat.id,
photo,
caption=caption,
@ -85,7 +86,7 @@ async def profile(client: Client, message: Message):
need_admin=True,
description=lang('block_des'),
parameters="(username/uid/reply)")
async def block_user(client: Client, message: Message):
async def block_user(message: Message):
""" Block a user. """
if len(message.parameter) > 1:
await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
@ -95,11 +96,9 @@ async def block_user(client: Client, message: Message):
user = message.obtain_user()
if not user:
return await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
try:
if await client.block_user(user):
with contextlib.suppress(Exception):
if await message.bot.block_user(user):
return await message.edit(f"{lang('block_success')} `{user}`")
except Exception: # noqa
pass
await message.edit(f"`{user}` {lang('block_exist')}")
@ -107,7 +106,7 @@ async def block_user(client: Client, message: Message):
need_admin=True,
description=lang('unblock_des'),
parameters="<username/uid/reply>")
async def unblock_user(client: Client, message: Message):
async def unblock_user(message: Message):
""" Unblock a user. """
if len(message.parameter) > 1:
await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
@ -117,9 +116,7 @@ async def unblock_user(client: Client, message: Message):
user = message.obtain_user()
if not user:
return await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
try:
if await client.unblock_user(user):
with contextlib.suppress(Exception):
if await message.bot.unblock_user(user):
return await message.edit(f"{lang('unblock_success')} `{user}`")
except Exception: # noqa
pass
await message.edit(f"`{user}` {lang('unblock_exist')}")

View File

@ -1 +1,91 @@
""" PagerMaid module for different ways to avoid users. """ from pyrogram import Client from pagermaid import log from pagermaid.single_utils import sqlite from pagermaid.utils import lang, Message from pagermaid.listener import listener @listener(is_plugin=False, outgoing=True, command="ghost", description=lang('ghost_des'), parameters="<true|false|status>") async def ghost(client: Client, message: Message): """ Toggles ghosting of a user. """ if len(message.parameter) != 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return myself = await client.get_me() 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')) sqlite["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')}") elif message.parameter[0] == "false": if message.chat_id == self_user_id: await message.edit(lang('ghost_e_mark')) return try: del sqlite["ghosted.chat_id." + str(message.chat_id)] except KeyError: 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')}") elif message.parameter[0] == "status": if sqlite.get("ghosted.chat_id." + str(message.chat_id), None): await message.edit(lang('ghost_e_exist')) else: 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="<true|false|status>") async def deny(client: Client, message: Message): """ Toggles denying of a user. """ if len(message.parameter) != 1: await message.edit(f"{lang('error_prefix')}{lang('arg_error')}") return myself = await client.get_me() 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')) sqlite["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')) return try: del sqlite["denied.chat_id." + str(message.chat_id)] except KeyError: 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("denied.chat_id." + str(message.chat_id), None): await message.edit(lang('deny_e_exist')) else: 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. """ if sqlite.get("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(_: Client, message: Message): """ Event handler to infinitely delete denied messages. """ if sqlite.get("denied.chat_id." + str(message.chat.id), None): await message.safe_delete()
""" PagerMaid module for different ways to avoid users. """
from pagermaid import log
from pagermaid.single_utils import sqlite
from pagermaid.utils import lang, Message
from pagermaid.listener import listener
@listener(is_plugin=False, outgoing=True, command="ghost",
description=lang('ghost_des'),
parameters="<true|false|status>")
async def ghost(message: Message):
""" Toggles ghosting of a user. """
if len(message.parameter) != 1:
await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
return
myself = await message.bot.get_me()
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'))
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')}")
elif message.parameter[0] == "false":
if message.chat_id == self_user_id:
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'))
await message.safe_delete()
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'))
else:
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="<true|false|status>")
async def deny(message: Message):
""" Toggles denying of a user. """
if len(message.parameter) != 1:
await message.edit(f"{lang('error_prefix')}{lang('arg_error')}")
return
myself = await message.bot.get_me()
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'))
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'))
return
try:
del sqlite[f"denied.chat_id.{str(message.chat_id)}"]
except KeyError:
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'))
else:
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(message: Message):
""" Event handler to infinitely read ghosted messages. """
if sqlite.get(f"ghosted.chat_id.{str(message.chat.id)}", None):
await message.bot.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. """
if sqlite.get(f"denied.chat_id.{str(message.chat.id)}", None):
await message.safe_delete()

View File

@ -1,10 +1,9 @@
""" Pagermaid backup and recovery plugin. """
import os
import sys
import tarfile
from traceback import format_exc
from pyrogram import Client
from pagermaid.config import Config
from pagermaid.listener import listener
from pagermaid.utils import upload_attachment, lang, Message
@ -42,7 +41,7 @@ def un_tar_gz(filename, dirs):
@listener(is_plugin=False, outgoing=True, command="backup",
description=lang('back_des'))
async def backup(_: Client, message: Message):
async def backup(message: Message):
await message.edit(lang('backup_process'))
# Remove old backup
@ -66,23 +65,21 @@ async def backup(_: Client, message: Message):
@listener(is_plugin=False, outgoing=True, command="recovery",
need_admin=True,
description=lang('recovery_des'))
async def recovery(_: Client, message: Message):
async def recovery(message: Message):
reply = message.reply_to_message
if reply.document: # Overwrite local backup
try:
if ".tar.gz" in reply.document.file_name: # Verify filename
await message.edit(lang('recovery_down'))
# Start download process
pgm_backup_zip_name = await reply.download() # noqa
else:
return await message.edit(lang('recovery_file_error'))
except Exception as e: # noqa
print(e, format_exc())
return await message.edit(lang('recovery_file_error'))
else:
if not reply.document:
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'))
# 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'))
# Extract backup files
await message.edit(lang('recovery_process'))
if not os.path.exists(pgm_backup_zip_name):
@ -96,4 +93,4 @@ async def recovery(_: Client, message: Message):
os.remove(pgm_backup_zip_name)
await message.edit(lang('recovery_success') + " " + lang('apt_reboot'))
exit(1)
sys.exit(1)

View File

@ -2,7 +2,6 @@
from datetime import datetime
from pyrogram import Client
from pytz import country_names, country_timezones, timezone
from pagermaid.config import Config
from pagermaid.listener import listener
@ -12,7 +11,7 @@ from pagermaid.utils import lang, Message
@listener(is_plugin=False, outgoing=True, command="time",
description=lang('time_des'),
parameters=lang('time_parameters'))
async def time(_: Client, message: Message):
async def time(message: Message):
""" For querying time. """
if len(message.parameter) == 1:
country = message.parameter[0].title()

View File

@ -1,33 +1,21 @@
""" The help module. """
from pyrogram import Client
from json import dump as json_dump
from os import listdir, sep
from pagermaid import help_messages, Config
from pagermaid.group_manager import enforce_permission
from pagermaid.modules.reload import reload_all
from pagermaid.utils import lang, Message, from_self, from_msg_get_sudo_uid
from pagermaid.listener import listener
import pathlib
@listener(is_plugin=False, command="help",
description=lang('help_des'),
parameters=f"<{lang('command')}>")
async def help_command(_: Client, message: Message):
async def help_command(message: Message):
""" The help new command,"""
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']
if message.arguments:
if message.arguments in help_messages:
if from_self(message) or \
@ -39,6 +27,20 @@ async def help_command(_: Client, message: Message):
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']
for command in sorted(help_messages, reverse=False):
if str(command) in support_commands:
continue
@ -62,7 +64,7 @@ async def help_command(_: Client, message: Message):
@listener(is_plugin=False, command="help_raw",
description=lang('help_des'),
parameters=f"<{lang('command')}>")
async def help_raw_command(_: Client, message: Message):
async def help_raw_command(message: Message):
""" The help raw command,"""
if message.arguments:
if message.arguments in help_messages:
@ -79,29 +81,29 @@ async def help_raw_command(_: Client, message: Message):
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')}** "
f"[{lang('help_source')}](https://t.me/PagerMaid_Modify)",
disable_web_page_preview=True)
await message.edit(
f"""{result[:-2]}\n**{lang('help_send')} ",help <{lang('command')}>" {lang('help_see')}** [{lang('help_source')}](https://t.me/PagerMaid_Modify)""",
disable_web_page_preview=True,
)
@listener(is_plugin=False, command="lang",
need_admin=True,
description=lang('lang_des'))
async def lang_change(_: Client, message: Message):
async def lang_change(message: Message):
to_lang = message.arguments
from_lang = Config.LANGUAGE
dir_, dir__ = listdir('languages/built-in'), []
for i in dir_:
if not i.find('yml') == -1:
if i.find('yml') != -1:
dir__.append(i[:-4])
with open('config.yml') as f:
file = f.read()
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') as f:
f.write(file)
await message.edit(f"{lang('lang_change_to')} {to_lang}, {lang('lang_reboot')}")
exit(1)
reload_all()
else:
await message.edit(f'{lang("lang_current_lang")} {Config.LANGUAGE}\n\n'
f'{lang("lang_all_lang")}{"".join(dir__)}')
@ -112,7 +114,7 @@ async def lang_change(_: Client, message: Message):
need_admin=True,
description=lang('alias_des'),
parameters='{list|del|set} <source> <to>')
async def alias_commands(_: Client, message: Message):
async def alias_commands(message: Message):
source_commands = []
to_commands = []
texts = []
@ -123,9 +125,12 @@ async def alias_commands(_: Client, message: Message):
await message.edit(lang('arg_error'))
return
elif len(message.parameter) == 1:
if not len(source_commands) == 0:
for i in range(0, len(source_commands)):
texts.append(f'`{source_commands[i]}` --> `{to_commands[i]}`')
if source_commands:
texts.extend(
f'`{source_commands[i]}` --> `{to_commands[i]}`'
for i in range(len(source_commands))
)
await message.edit(lang('alias_list') + '\n\n' + '\n'.join(texts))
else:
await message.edit(lang('alias_no'))
@ -136,7 +141,7 @@ async def alias_commands(_: Client, message: Message):
with open(f"data{sep}alias.json", 'w') as f:
json_dump(Config.alias_dict, f)
await message.edit(lang('alias_success'))
exit(1)
reload_all()
except KeyError:
await message.edit(lang('alias_no_exist'))
return
@ -150,4 +155,4 @@ async def alias_commands(_: Client, message: Message):
with open(f"data{sep}alias.json", 'w') as f:
json_dump(Config.alias_dict, f)
await message.edit(lang('alias_success'))
exit(1)
reload_all()

View File

@ -1,5 +1,5 @@
""" Pagermaid message plugin. """
from pyrogram import Client
from pyrogram.errors import Forbidden, FloodWait
from pagermaid import log
@ -10,29 +10,29 @@ from pagermaid.utils import lang, Message
@listener(is_plugin=False, outgoing=True, command="id",
description=lang("id_des"))
async def userid(_: Client, message: Message):
async def userid(message: Message):
""" Query the UserID of the sender of the message you replied to. """
reply = message.reply_to_message
text = "Message ID: `" + str(message.id) + "`\n\n"
text = f"Message ID: `{str(message.id)}" + "`\n\n"
text += "**Chat**\nid:`" + str(message.chat.id) + "`\n"
msg_from = message.chat
if msg_from.type == "private":
try:
text += "first_name: `" + msg_from.first_name + "`\n"
text += f"first_name: `{msg_from.first_name}" + "`\n"
except TypeError:
text += "**死号**\n"
if msg_from.last_name:
text += "last_name: `" + msg_from.last_name + "`\n"
text += f"last_name: `{msg_from.last_name}" + "`\n"
if msg_from.username:
text += "username: @" + msg_from.username + "\n"
text += f"username: @{msg_from.username}" + "\n"
if msg_from.type in ["supergroup", "channel"]:
text += "title: `" + msg_from.title + "`\n"
text += f"title: `{msg_from.title}" + "`\n"
try:
if msg_from.username:
text += "username: @" + msg_from.username + "\n"
text += f"username: @{msg_from.username}" + "\n"
except AttributeError:
return await message.edit(lang("leave_not_group"))
text += "protected: `" + str(msg_from.has_protected_content) + "`\n"
text += f"protected: `{str(msg_from.has_protected_content)}" + "`\n"
if reply:
text += "\n" + lang('id_hint') + "\nMessage ID: `" + str(reply.id) + \
"`\n\n**User**\nid: `" + str(reply.from_user.id) + "`"
@ -83,7 +83,7 @@ async def userid(_: Client, message: Message):
@listener(is_plugin=False, outgoing=True, command="uslog",
description=lang('uslog_des'),
parameters="<string>")
async def uslog(_: Client, message: Message):
async def uslog(message: Message):
""" Forwards a message into log group """
if Config.LOG:
if message.reply_to_message:
@ -101,7 +101,7 @@ async def uslog(_: Client, message: Message):
@listener(is_plugin=False, outgoing=True, command="log",
description=lang('log_des'),
parameters="<string>")
async def logging(_: Client, message: Message):
async def logging(message: Message):
""" Forwards a message into log group """
if Config.LOG:
if message.reply_to_message:
@ -119,10 +119,9 @@ async def logging(_: Client, message: Message):
@listener(is_plugin=False, outgoing=True, command="re",
description=lang('re_des'),
parameters=lang('re_parameters'))
async def re(_: Client, message: Message):
async def re(message: Message):
""" Forwards a message into this group """
reply = message.reply_to_message
if reply:
if reply := message.reply_to_message:
if message.arguments == '':
num = 1
else:
@ -130,10 +129,10 @@ async def re(_: Client, message: Message):
num = int(message.arguments)
if num > 100:
await message.edit(lang('re_too_big'))
except: # noqa
except Exception:
return await message.edit(lang('re_arg_error'))
await message.safe_delete()
for nums in range(0, num):
for _ in range(num):
try:
if not message.chat.has_protected_content:
await reply.forward(reply.chat.id)

View File

@ -1,30 +1,29 @@
""" PagerMaid module to manage plugins. """
import contextlib
import json
import importlib
from re import search, I
from os import remove, rename, chdir, path, sep
from os.path import exists
from shutil import copyfile, move
from glob import glob
from pyrogram import Client
from pagermaid import log, working_dir, Config
from pagermaid import log, working_dir, Config, scheduler
from pagermaid.listener import listener
from pagermaid.single_utils import safe_remove
from pagermaid.utils import upload_attachment, lang, Message, client
from pagermaid.modules import plugin_list as active_plugins, __list_plugins
from pagermaid.modules.reload import reload_all
def remove_plugin(name):
plugin_directory = f"{working_dir}{sep}plugins{sep}"
try:
with contextlib.suppress(FileNotFoundError):
remove(f"{plugin_directory}{name}.py")
except FileNotFoundError:
pass
try:
with contextlib.suppress(FileNotFoundError):
remove(f"{plugin_directory}{name}.py.disabled")
except FileNotFoundError:
pass
def move_plugin(file_path):
@ -55,7 +54,7 @@ def update_version(plugin_name, version):
diagnostics=False,
description=lang('apt_des'),
parameters=lang('apt_parameters'))
async def plugin(__: Client, message: Message):
async def plugin(message: Message):
if len(message.parameter) == 0:
await message.edit(lang('arg_error'))
return
@ -81,7 +80,7 @@ async def plugin(__: Client, message: Message):
f"{path.basename(file_path)[:-3]} {lang('apt_installed')},"
f"{lang('apt_reboot')}")
await log(f"{lang('apt_install_success')} {path.basename(file_path)[:-3]}.")
exit(0)
reload_all()
elif len(message.parameter) >= 2:
process_list = message.parameter
message = await message.edit(lang('apt_processing'))
@ -133,24 +132,24 @@ async def plugin(__: Client, message: Message):
text += lang('apt_reboot')
await message.edit(text)
if restart:
exit(0)
reload_all()
else:
await message.edit(lang('arg_error'))
elif message.parameter[0] == "remove":
if len(message.parameter) == 2:
if exists(f"{plugin_directory}{message.parameter[1]}.py") or \
exists(f"{plugin_directory}{message.parameter[1]}.py.disabled"):
safe_remove(f"{plugin_directory}{message.parameter[1]}.py")
safe_remove(f"{plugin_directory}{message.parameter[1]}.py.disabled")
with open(f"{plugin_directory}version.json", 'r', encoding="utf-8") as f:
version_json = json.load(f)
version_json[message.parameter[1]] = "0.0"
with open(f"{plugin_directory}version.json", 'w') as f:
json.dump(version_json, f)
remove_plugin(message.parameter[1])
if exists(f"{plugin_directory}version.json"):
with open(f"{plugin_directory}version.json", 'r', encoding="utf-8") as f:
version_json = json.load(f)
version_json[message.parameter[1]] = "0.0"
with open(f"{plugin_directory}version.json", 'w') as f:
json.dump(version_json, f)
await message.edit(f"{lang('apt_remove_success')} {message.parameter[1]}, "
f"{lang('apt_reboot')} ")
await log(f"{lang('apt_remove')} {message.parameter[1]}.")
exit(0)
reload_all()
elif "/" in message.parameter[1]:
await message.edit(lang('arg_error'))
else:
@ -201,7 +200,7 @@ async def plugin(__: Client, message: Message):
await message.edit(f"{lang('apt_plugin')} {message.parameter[1]} "
f"{lang('apt_enable')},{lang('apt_reboot')}")
await log(f"{lang('apt_enable')} {message.parameter[1]}.")
exit(0)
reload_all()
else:
await message.edit(lang('apt_not_exist'))
else:
@ -214,7 +213,7 @@ async def plugin(__: Client, message: Message):
await message.edit(f"{lang('apt_plugin')} {message.parameter[1]} "
f"{lang('apt_disable')},{lang('apt_reboot')}")
await log(f"{lang('apt_disable')} {message.parameter[1]}.")
exit(0)
reload_all()
else:
await message.edit(lang('apt_not_exist'))
else:
@ -262,7 +261,7 @@ async def plugin(__: Client, message: Message):
un_need_update += "\n`" + key + "`:Ver " + value
else:
need_update_list.extend([key])
need_update += "\n`" + key + "`:Ver " + value + " --> Ver " + i['version']
need_update += "\n<code>" + key + "</code>:Ver " + value + " > Ver " + i['version']
continue
if un_need_update == f"{lang('apt_no_update')}:":
un_need_update = ""
@ -288,7 +287,7 @@ async def plugin(__: Client, message: Message):
with open(f"{plugin_directory}version.json", "w") as f:
json.dump(version_json, f)
await message.edit(f"<b>{lang('apt_name')}</b>\n\n" + lang("apt_reading_list") + need_update)
exit(0)
reload_all()
elif message.parameter[0] == "search":
if len(message.parameter) == 1:
await message.edit(lang("apt_search_no_name"))
@ -354,5 +353,9 @@ async def plugin(__: Client, message: Message):
await message.edit(lang("apt_why_not_install_a_plugin"))
else:
await message.edit(",apt install " + " ".join(list_plugin))
elif message.parameter[0] == "reload":
# bot.dispatcher.remove_all_handlers() # noqa
scheduler.remove_all_jobs()
importlib.reload(importlib.import_module("plugins.sign"))
else:
await message.edit(lang("arg_error"))

View File

@ -2,17 +2,17 @@
from asyncio import sleep
from pyrogram import Client
from pagermaid import log
from pagermaid.listener import listener
from pagermaid.utils import lang, Message
import contextlib
@listener(is_plugin=False, outgoing=True, command="prune",
need_admin=True,
description=lang('prune_des'))
async def prune(client: Client, message: Message):
async def prune(message: Message):
""" Purge every single message after the message you replied to. """
if not message.reply_to_message:
await message.edit(lang('not_reply'))
@ -20,8 +20,8 @@ async def prune(client: Client, message: Message):
input_chat = message.chat.id
messages = []
count = 0
async for msg in client.get_chat_history(input_chat,
limit=message.id - message.reply_to_message.id + 1):
async for msg in message.bot.get_chat_history(input_chat,
limit=message.id - message.reply_to_message.id + 1):
if msg.id < message.reply_to_message.id:
break
messages.append(msg.id)
@ -29,13 +29,13 @@ async def prune(client: Client, message: Message):
if msg.reply_to_message:
messages.append(msg.reply_to_message.id)
if len(messages) == 100:
await client.delete_messages(input_chat, messages)
await message.bot.delete_messages(input_chat, messages)
messages = []
if messages:
await client.delete_messages(input_chat, messages)
await message.bot.delete_messages(input_chat, messages)
await log(f"{lang('prune_hint1')} {str(count)} {lang('prune_hint2')}")
notification = await send_prune_notify(client, message, count, count)
notification = await send_prune_notify(message, count, count)
await sleep(1)
await notification.delete()
@ -44,14 +44,14 @@ async def prune(client: Client, message: Message):
need_admin=True,
description=lang('sp_des'),
parameters=lang('sp_parameters'))
async def self_prune(client: Client, message: Message):
async def self_prune(message: Message):
""" Deletes specific amount of messages you sent. """
msgs = []
count_buffer = 0
if not len(message.parameter) == 1:
if len(message.parameter) != 1:
if not message.reply_to_message:
return await message.edit(lang('arg_error'))
async for msg in client.search_messages(
async for msg in message.bot.search_messages(
message.chat.id,
from_user="me",
offset=message.reply_to_message.id,
@ -59,15 +59,15 @@ async def self_prune(client: Client, message: Message):
msgs.append(msg.id)
count_buffer += 1
if len(msgs) == 100:
await client.delete_messages(message.chat.id, msgs)
await message.bot.delete_messages(message.chat.id, msgs)
msgs = []
if msgs:
await client.delete_messages(message.chat.id, msgs)
await message.bot.delete_messages(message.chat.id, msgs)
if count_buffer == 0:
await message.delete()
count_buffer += 1
await log(f"{lang('prune_hint1')}{lang('sp_hint')} {str(count_buffer)} {lang('prune_hint2')}")
notification = await send_prune_notify(client, message, count_buffer, count_buffer)
notification = await send_prune_notify(message, count_buffer, count_buffer)
await sleep(1)
await notification.delete()
return
@ -77,37 +77,38 @@ async def self_prune(client: Client, message: Message):
except ValueError:
await message.edit(lang('arg_error'))
return
async for msg in client.search_messages(message.chat.id, from_user="me"):
async for msg in message.bot.search_messages(message.chat.id, from_user="me"):
if count_buffer == count:
break
msgs.append(msg.id)
count_buffer += 1
if len(msgs) == 100:
await client.delete_messages(message.chat.id, msgs)
await message.bot.delete_messages(message.chat.id, msgs)
msgs = []
if msgs:
await client.delete_messages(message.chat.id, msgs)
await log(f"{lang('prune_hint1')}{lang('sp_hint')} {str(count_buffer)} / {str(count)} {lang('prune_hint2')}")
try:
notification = await send_prune_notify(client, message, count_buffer, count)
await message.bot.delete_messages(message.chat.id, msgs)
await log(
f"{lang('prune_hint1')}{lang('sp_hint')} {str(count_buffer)} / {count} {lang('prune_hint2')}"
)
with contextlib.suppress(ValueError):
notification = await send_prune_notify(message, count_buffer, count)
await sleep(1)
await notification.delete()
except ValueError:
pass
@listener(is_plugin=False, outgoing=True, command="yourprune",
need_admin=True,
description=lang('yp_des'),
parameters=lang('sp_parameters'))
async def your_prune(client: Client, message: Message):
async def your_prune(message: Message):
""" Deletes specific amount of messages someone sent. """
if not message.reply_to_message:
return await message.edit(lang('not_reply'))
target = message.reply_to_message
if not target.from_user:
return await message.edit(lang('not_reply'))
if not len(message.parameter) == 1:
if len(message.parameter) != 1:
return await message.edit(lang('arg_error'))
count = 0
try:
@ -118,13 +119,16 @@ async def your_prune(client: Client, message: Message):
except Exception: # noqa
pass
count_buffer = 0
async for msg in client.search_messages(message.chat.id, from_user=target.from_user.id):
async for msg in message.bot.search_messages(message.chat.id, from_user=target.from_user.id):
if count_buffer == count:
break
await msg.delete()
count_buffer += 1
await log(f"{lang('prune_hint1')}{lang('yp_hint')} {str(count_buffer)} / {str(count)} {lang('prune_hint2')}")
notification = await send_prune_notify(client, message, count_buffer, count)
await log(
f"{lang('prune_hint1')}{lang('yp_hint')} {str(count_buffer)} / {count} {lang('prune_hint2')}"
)
notification = await send_prune_notify(message, count_buffer, count)
await sleep(1)
await notification.delete()
@ -132,22 +136,19 @@ async def your_prune(client: Client, message: Message):
@listener(is_plugin=False, outgoing=True, command="del",
need_admin=True,
description=lang('del_des'))
async def delete(_: Client, message: Message):
async def delete(message: Message):
""" Deletes the message you replied to. """
target = message.reply_to_message
if target:
try:
if target := message.reply_to_message:
with contextlib.suppress(Exception):
await target.delete()
except Exception as e: # noqa
pass
await message.delete()
await log(lang('del_notification'))
else:
await message.delete()
async def send_prune_notify(client, message, count_buffer, count):
return await client.send_message(
async def send_prune_notify(message: Message, count_buffer, count):
return await message.bot.send_message(
message.chat.id,
"%s %s / %s %s" % (lang('spn_deleted'), str(count_buffer), str(count), lang('prune_hint2'))
f"{lang('spn_deleted')} {str(count_buffer)} / {str(count)} {lang('prune_hint2')}",
)

View File

@ -0,0 +1,45 @@
import importlib
import pagermaid.config
import pagermaid.modules
from pagermaid import bot, logs, help_messages, all_permissions
from pagermaid.listener import listener
from pagermaid.utils import lang, Message
def reload_all():
bot.dispatcher.remove_all_handlers()
bot.job.remove_all_jobs()
loaded_plugins = list(pagermaid.modules.plugin_list)
loaded_plugins.extend(iter(pagermaid.modules.module_list))
# init
importlib.reload(pagermaid.modules)
importlib.reload(pagermaid.config)
help_messages.clear()
all_permissions.clear()
importlib.reload(pagermaid.modules)
for module_name in pagermaid.modules.module_list:
try:
module = importlib.import_module(f"pagermaid.modules.{module_name}")
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}")
for plugin_name in pagermaid.modules.plugin_list:
try:
plugin = importlib.import_module(f"plugins.{plugin_name}")
if plugin_name in loaded_plugins:
importlib.reload(plugin)
except BaseException as exception:
logs.info(f"{lang('module')} {plugin_name} {lang('error')}: {exception}")
pagermaid.modules.plugin_list.remove(plugin_name)
@listener(is_plugin=False, command="reload",
need_admin=True,
description=lang('reload_des'))
async def reload_plugins(message: Message):
""" To reload plugins. """
reload_all()
await message.edit(lang("reload_ok"))

View File

@ -1,9 +1,9 @@
""" PagerMaid module that contains utilities related to system status. """
from datetime import datetime
from datetime import datetime, timezone
from platform import uname, python_version
from sys import platform
from pyrogram import Client, __version__
from pyrogram import __version__
from pyrogram.raw.functions import Ping
from pyrogram.enums.parse_mode import ParseMode
@ -21,7 +21,7 @@ from pagermaid.utils import lang, Message, execute
@listener(is_plugin=False, command="sysinfo",
description=lang('sysinfo_des'))
async def sysinfo(_: Client, message: Message):
async def sysinfo(message: Message):
""" Retrieve system information via neofetch. """
if not Config.SILENT:
message = await message.edit(lang("sysinfo_loading"))
@ -33,7 +33,7 @@ async def sysinfo(_: Client, message: Message):
@listener(is_plugin=False, command="status",
description=lang('status_des'))
async def status(_: Client, message: Message):
async def status(message: Message):
# database
# database = lang('status_online') if redis_status() else lang('status_offline')
# uptime https://gist.github.com/borgstrom/936ca741e885a1438c374824efb038b3
@ -55,7 +55,7 @@ async def status(_: Client, message: Message):
time_form = time_form.replace(key, value)
return time_form
current_time = datetime.utcnow()
current_time = datetime.now(timezone.utc)
uptime_sec = (current_time - start_time).total_seconds()
uptime = await human_time_duration(int(uptime_sec))
text = (f"**{lang('status_hint')}** \n"
@ -72,10 +72,10 @@ async def status(_: Client, message: Message):
@listener(is_plugin=False, command="ping",
description=lang('ping_des'))
async def ping(client: Client, message: Message):
async def ping(message: Message):
""" Calculates latency between PagerMaid and Telegram. """
start = datetime.now()
await client.invoke(Ping(ping_id=0))
await message.bot.invoke(Ping(ping_id=0))
end = datetime.now()
ping_duration = (end - start).microseconds / 1000
start = datetime.now()
@ -180,7 +180,8 @@ def neofetch_win():
gpu = [f' {g.strip()}' for g in gpu[1:]][0].strip()
ram = get_ram()
disks = '\n'.join(partitions())
text = f'<code>{user_name}@{host_name}\n---------\nOS: {os}\nUptime: {uptime}\n' \
f'Motherboard: {mboard}\nCPU: {cpu}\nGPU: {gpu}\nMemory: {ram}\n' \
f'Disk:\n{disks}</code>'
return text
return (
f'<code>{user_name}@{host_name}\n---------\nOS: {os}\nUptime: {uptime}\n'
f'Motherboard: {mboard}\nCPU: {cpu}\nGPU: {gpu}\nMemory: {ram}\n'
f'Disk:\n{disks}</code>'
)

View File

@ -1,5 +1,3 @@
from pyrogram import Client
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, \
@ -10,18 +8,17 @@ from pagermaid.single_utils import get_sudo_list
def from_msg_get_sudo_id(message: Message) -> int:
reply = message.reply_to_message
if reply:
if reply := message.reply_to_message:
return reply.from_user.id if reply.from_user else reply.sender_chat.id
else:
return message.chat.id
@listener(is_plugin=False, outgoing=True, command="sudo",
@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):
async def sudo_change(message: Message):
""" To enable or disable sudo of your userbot. """
input_str = message.arguments
sudo = get_sudo_list()
@ -79,28 +76,30 @@ async def sudo_change(client: Client, message: Message):
for i in sudo:
try:
if i > 0:
user = await client.get_users(i)
user = await message.bot.get_users(i)
text += f"{user.mention()} - {' '.join(permissions.get_roles_for_user(str(i)))}\n"
else:
chat = await client.get_chat(i)
chat = await message.bot.get_chat(i)
text += f"{chat.title} - {' '.join(permissions.get_roles_for_user(str(i)))}\n"
for j in permissions.get_permissions_for_user(str(i)):
text += f"{'-' if j[2] == 'ejection' else ''}{j[1]}\n"
except:
except Exception:
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:
from_id = from_msg_get_sudo_id(message)
if message.parameter[0] == "glist":
data = permissions.get_permissions_for_user(str(message.parameter[1]))
if data:
text = f"**{message.parameter[1]} {lang('sudo_group_list')}**\n\n"
for i in data:
text += f" • `{'-' if i[2] == 'ejection' else ''}{i[1]}`\n"
return await message.edit(text)
else:
if not (
data := permissions.get_permissions_for_user(
str(message.parameter[1])
)
):
return await edit_delete(message, f"__{lang('sudo_group_list')}__")
text = f"**{message.parameter[1]} {lang('sudo_group_list')}**\n\n"
for i in data:
text += f" • `{'-' if i[2] == 'ejection' else ''}{i[1]}`\n"
return await message.edit(text)
if from_id not in sudo:
return await edit_delete(message, f"__{lang('sudo_no')}__")
elif message.parameter[0] == "gaddu":

View File

@ -6,8 +6,6 @@ from sys import exit
from platform import node
from getpass import getuser
from pyrogram import Client
from pagermaid import bot
from pagermaid.listener import listener
from pagermaid.utils import attach_log, execute, Message, lang
@ -17,7 +15,7 @@ from pagermaid.utils import attach_log, execute, Message, lang
need_admin=True,
description=lang('sh_des'),
parameters=lang('sh_parameters'))
async def sh(_: Client, message: Message):
async def sh(message: Message):
""" Use the command-line from Telegram. """
user = getuser()
command = message.arguments
@ -28,9 +26,9 @@ async def sh(_: Client, message: Message):
return
message = await message.edit(
f"`{user}`@{hostname} ~"
f"\n> `$` {command}"
)
f"`{user}`@{hostname} ~"
f"\n> `$` {command}"
)
result = await execute(command)
@ -40,10 +38,10 @@ async def sh(_: Client, 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
@ -51,7 +49,7 @@ async def sh(_: Client, message: Message):
@listener(is_plugin=False, command="restart",
need_admin=True,
description=lang('restart_des'))
async def restart(_: Client, message: Message):
async def restart(message: Message):
""" To re-execute PagerMaid. """
if not message.text[0].isalpha():
await message.edit(lang('restart_log'))
@ -62,7 +60,7 @@ async def restart(_: Client, message: Message):
need_admin=True,
description=lang('eval_des'),
parameters=lang('eval_parameters'))
async def sh_eval(_: Client, message: Message):
async def sh_eval(message: Message):
""" Run python commands from Telegram. """
try:
cmd = message.text.split(" ", maxsplit=1)[1]
@ -89,14 +87,9 @@ async def sh_eval(_: Client, message: Message):
evaluation = stdout
else:
evaluation = "Success"
final_output = (
"**>>>** ```{}``` \n```{}```".format(
cmd,
evaluation,
)
)
final_output = f"**>>>** ```{cmd}``` \n```{evaluation}```"
if len(final_output) > 4096:
message = await message.edit("**>>>** ```{}```".format(cmd))
message = await message.edit(f"**>>>** ```{cmd}```")
await attach_log(bot, evaluation, message.chat.id, "output.log", message.id)
else:
await message.edit(final_output)
@ -104,11 +97,14 @@ async def sh_eval(_: Client, message: Message):
async def aexec(code, event, client):
exec(
f"async def __aexec(e, client): "
+ "\n msg = message = e"
+ "\n reply = message.reply_to_message"
+ "\n chat = e.chat"
+ "".join(f"\n {x}" for x in code.split("\n")),
(
(
("async def __aexec(e, client): " + "\n msg = message = e")
+ "\n reply = message.reply_to_message"
)
+ "\n chat = e.chat"
)
+ "".join(f"\n {x}" for x in code.split("\n"))
)
return await locals()["__aexec"](event, client)

View File

@ -1,6 +1,4 @@
from sys import executable
from pyrogram import Client
from sys import executable, exit
from pagermaid.listener import listener
from pagermaid.utils import lang, execute, Message, alias_command
@ -10,7 +8,7 @@ from pagermaid.utils import lang, execute, Message, alias_command
need_admin=True,
description=lang('update_des'),
parameters="<true/debug>")
async def update(_: Client, message: Message):
async def update(message: Message):
await execute('git fetch --all')
if len(message.parameter) > 0:
await execute('git reset --hard origin/master')

25
pagermaid/scheduler.py Normal file
View File

@ -0,0 +1,25 @@
import contextlib
import datetime
import pytz
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from pagermaid.single_utils import Message
scheduler = AsyncIOScheduler(timezone="Asia/ShangHai")
async def delete_message(message: Message) -> bool:
with contextlib.suppress(Exception):
await message.delete()
return True
return False
def add_delete_message_job(message: Message, delete_seconds: int = 60):
scheduler.add_job(
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("Asia/Shanghai")) + datetime.timedelta(seconds=delete_seconds),
replace_existing=True)

View File

@ -1,6 +1,11 @@
import contextlib
from os import sep, remove, mkdir
from os.path import exists
from typing import List, Optional
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from httpx import AsyncClient
from pyrogram import Client
from pyrogram.types import Message
from sqlitedict import SqliteDict
@ -19,15 +24,19 @@ def _status_sudo():
def safe_remove(name: str) -> None:
try:
with contextlib.suppress(FileNotFoundError):
remove(name)
except FileNotFoundError:
pass
class Client(Client): # noqa
job: Optional[AsyncIOScheduler] = None
class Message(Message): # noqa
arguments: str
parameter: List
bot: Client
request: Optional[AsyncClient] = None
def obtain_message(self) -> Optional[str]:
""" Obtains a message from either the reply message or command arguments. """
@ -37,5 +46,8 @@ class Message(Message): # noqa
""" Obtains a user from either the reply message or command arguments. """
return
async def delay_delete(self, delete_seconds: int = 60) -> Optional[bool]:
return
async def safe_delete(self, revoke: bool = True) -> None:
return

View File

@ -1,3 +1,4 @@
import contextlib
import subprocess
from importlib.util import find_spec
from os.path import exists
@ -18,22 +19,18 @@ from pagermaid.single_utils import _status_sudo, get_sudo_list, Message, sqlite
def lang(text: str) -> str:
""" i18n """
result = Config.lang_dict.get(text, text)
return result
return Config.lang_dict.get(text, text)
def alias_command(command: str, disallow_alias: bool = False) -> str:
""" alias """
if disallow_alias:
return command
return Config.alias_dict.get(command, command)
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. """
file = open(file_name, "w+")
file.write(plaintext)
file.close()
with open(file_name, "w+") as file:
file.write(plaintext)
try:
await bot.send_document(
"PagerMaid_Modify_bot",
@ -48,9 +45,8 @@ 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. """
file = open(file_name, "w+")
file.write(plaintext)
file.close()
with open(file_name, "w+") as file:
file.write(plaintext)
await bot.send_document(
chat_id,
file_name,
@ -141,15 +137,9 @@ async def edit_delete(message: Message,
def get_permission_name(is_plugin: bool, need_admin: bool, command: str) -> str:
""" Get permission name. """
if is_plugin:
if need_admin:
return f"plugins_root.{command}"
else:
return f"plugins.{command}"
return f"plugins_root.{command}" if need_admin else f"plugins.{command}"
else:
if need_admin:
return f"system.{command}"
else:
return f"modules.{command}"
return f"system.{command}" if need_admin else f"modules.{command}"
def sudo_filter(permission: str):
@ -196,11 +186,10 @@ async def process_exit(start: int, _client, message=None):
if start and data and cid and mid:
msg: Message = await _client.get_messages(cid, mid)
if msg:
try:
await msg.edit((msg.text if msg.from_user.is_self and msg.text else "") +
f'\n\n> {lang("restart_complete")}')
except Exception as e: # noqa
pass
with contextlib.suppress(Exception):
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")}')
del sqlite["exit_msg"]
if message:
sqlite["exit_msg"] = {"cid": message.chat.id, "mid": message.id}

View File

@ -25,11 +25,10 @@ from typing import Optional, List
import pyrogram
from pagermaid.single_utils import get_sudo_list, Message
from pagermaid.scheduler import add_delete_message_job
from ..utils import patch, patchable
loop = asyncio.get_event_loop()
class ListenerCanceled(Exception):
pass
@ -53,14 +52,14 @@ class Client:
chat = await self.get_chat(chat_id)
chat_id = chat.id
future = loop.create_future()
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}
})
return await asyncio.wait_for(future, timeout)
return await asyncio.wait_for(future, timeout, loop=self.loop)
@patchable
async def ask(self, chat_id, text, filters=None, timeout=None, *args, **kwargs):
@ -144,6 +143,7 @@ class User(pyrogram.types.User):
def cancel_listener(self):
return self._client.cancel_listener(self.id)
# pagermaid-pyro
@ -163,7 +163,9 @@ class Message(pyrogram.types.Message):
@patchable
def obtain_message(self) -> Optional[str]:
""" Obtains a message from either the reply message or command arguments. """
return self.arguments if self.arguments else (self.reply_to_message.text if self.reply_to_message else None)
return self.arguments or (
self.reply_to_message.text if self.reply_to_message else None
)
@patchable
def obtain_user(self) -> Optional[int]:
@ -185,6 +187,10 @@ class Message(pyrogram.types.Message):
user = self.chat.id
return user
@patchable
async def delay_delete(self, delay: int = 60):
add_delete_message_job(self, delay)
@patchable
async def edit_text(
self,
@ -219,13 +225,12 @@ class Message(pyrogram.types.Message):
disable_web_page_preview=disable_web_page_preview,
reply_markup=reply_markup
)
else:
if not no_reply:
msg = await self.reply(
text=text,
parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview
)
elif not no_reply:
msg = await self.reply(
text=text,
parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview
)
else:
try:
msg = await self._client.edit_message_text(
@ -238,9 +243,7 @@ class Message(pyrogram.types.Message):
reply_markup=reply_markup
)
except pyrogram.errors.exceptions.forbidden_403.MessageAuthorRequired: # noqa
if no_reply:
pass
else:
if not no_reply:
msg = await self.reply(
text=text,
parse_mode=parse_mode,
@ -256,11 +259,26 @@ class Message(pyrogram.types.Message):
document="output.log",
reply_to_message_id=self.id
)
if msg:
msg.parameter = self.parameter
msg.arguments = self.arguments
return msg
else:
if not msg:
return self
msg.parameter = self.parameter
msg.arguments = self.arguments
return msg
edit = edit_text
@patch(pyrogram.dispatcher.Dispatcher) # noqa
class Dispatcher(pyrogram.dispatcher.Dispatcher): # noqa
@patchable
def remove_all_handlers(self):
async def fn():
for lock in self.locks_list:
await lock.acquire()
self.groups.clear()
for lock in self.locks_list:
lock.release()
self.loop.create_task(fn())

View File

@ -35,12 +35,12 @@ class Pagination:
offset = (page-1)*quant_per_page
stop = offset+quant_per_page
cutted = self.objects[offset:stop]
total = len(self.objects)
pages_range = [*range(1, math.ceil(total/quant_per_page)+1)] # each item is a page
last_page = len(pages_range)
nav = []
if page <= 3:
for n in [1,2,3]:
@ -57,29 +57,36 @@ class Pagination:
(f'{last_page} »' if last_page > 5 else last_page, self.page_data(last_page))
)
elif page >= last_page-2:
nav.extend([
(f'« 1' if last_page-4 > 1 else 1, self.page_data(1)),
(f' {last_page-3}' if last_page-4 > 1 else last_page-3, self.page_data(last_page-3))
])
nav.extend(
[
('« 1' if last_page > 5 else 1, self.page_data(1)),
(
f' {last_page-3}' if last_page > 5 else last_page - 3,
self.page_data(last_page - 3),
),
]
)
for n in range(last_page-2, last_page+1):
text = f"· {n} ·" if n == page else n
nav.append( (text, self.page_data(n)) )
else:
nav = [
(f'« 1', self.page_data(1)),
(f' {page-1}', self.page_data(page-1)),
('« 1', self.page_data(1)),
(f' {page-1}', self.page_data(page - 1)),
(f'· {page} ·', "noop"),
(f'{page+1} ', self.page_data(page+1)),
(f'{page+1} ', self.page_data(page + 1)),
(f'{last_page} »', self.page_data(last_page)),
]
buttons = []
for item in cutted:
buttons.append(
(self.item_title(item, page), self.item_data(item, page))
)
buttons = [
(self.item_title(item, page), self.item_data(item, page))
for item in cutted
]
kb_lines = array_chunk(buttons, columns)
if last_page > 1:
kb_lines.append(nav)
return kb_lines

View File

@ -25,7 +25,7 @@ def patch(obj):
def wrapper(container):
for name,func in filter(is_patchable, container.__dict__.items()):
old = getattr(obj, name, None)
setattr(obj, 'old'+name, old)
setattr(obj, f'old{name}', old)
setattr(obj, name, func)
return container
return wrapper