diff --git a/README.md b/README.md index 2aa532d..46542d6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com)

-#### _A Simple, Fast, Customizable Userbot for Telegram._ +#### _A Simple, Fast, Customizable Userbot for Telegram made after Dragon-Userbot abandoned._

Installation

diff --git a/install.py b/install.py index cb75ff4..4be1882 100644 --- a/install.py +++ b/install.py @@ -1,18 +1,18 @@ -#  Moon-Userbot - telegram userbot -#  Copyright (C) 2020-present Moon Userbot Organization +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization # -#  This program is free software: you can redistribute it and/or modify -#  it is under the terms of the GNU General Public License as published by -#  the Free Software Foundation, either version 3 of the License, or -#  (at your option) any later version. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. -#  You should have received a copy of the GNU General Public License -#  along with this program.  If not, see . +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import datetime import sys @@ -21,51 +21,46 @@ from pyrogram import Client from utils import config if __name__ == "__main__": -app = Client( - "my_account", - api_id = config.api_id, - api_hash = config.api_hash, - hide_password = True, - test_mode = config.test_server, -) + app = Client( + "my_account", + api_id=config.api_id, + api_hash=config.api_hash, + hide_password=True, + test_mode=config.test_server, + ) -if config.db_type in ["mongo", "mongodb"]: -from pymongo import MongoClient, errors + if config.db_type in ["mongo", "mongodb"]: + from pymongo import MongoClient, errors -db = MongoClient(config.db_url) -try: -db.server_info() -except errors.ConnectionFailure as e: -raise RuntimeError( - "MongoDB server isn't available! " -f"Provided url:  { - config.db_url - }. " - "Enter valid URL and restart installation" -) from e + db = MongoClient(config.db_url) + try: + db.server_info() + except errors.ConnectionFailure as e: + raise RuntimeError( + "MongoDB server isn't available! " + f"Provided url: {config.db_url}. " + "Enter valid URL and restart installation" + ) from e -install_type = sys.argv[1] if len(sys.argv) > 1 else "3" -if install_type == "1": -restart = "pm2 restart Moon" -elif install_type == "2": -restart = "sudo systemctl restart Moon" -else : -restart = "cd Moon-Userbot/ && python main.py" + install_type = sys.argv[1] if len(sys.argv) > 1 else "3" + if install_type == "1": + restart = "pm2 restart Moon" + elif install_type == "2": + restart = "sudo systemctl restart Moon" + else: + restart = "cd Moon-Userbot/ && python main.py" -app.start() -try: -app.send_message( - "me", -f"[ { - datetime.datetime.now()}] Moon-Userbot launched! \n" - "Channel: @moonuserbot\n" - "Custom modules: @moonub_modules\n" - "Chat [RU]: @moonub_chat\n" -f"For restart, enter:\n" -f" { - restart - }", -) -except Exception: -pass -app.stop() \ No newline at end of file + app.start() + try: + app.send_message( + "me", + f"[{datetime.datetime.now()}] Moon-Userbot launched! \n" + "Channel: @moonuserbot\n" + "Custom modules: @moonub_modules\n" + "Chat [RU]: @moonub_chat\n" + f"For restart, enter:\n" + f"{restart}", + ) + except Exception: + pass + app.stop() diff --git a/install.sh b/install.sh index 418d19b..1f74d3f 100644 --- a/install.sh +++ b/install.sh @@ -1,159 +1,164 @@ #!/bin/bash if command -v termux-setup-storage; then -echo For termux, please use https://raw.githubusercontent.com/The-MoonTg-project/Moon-Userbot/main/termux-install.sh -exit 1 + echo For termux, please use https://raw.githubusercontent.com/The-MoonTg-project/Moon-Userbot/main/termux-install.sh + exit 1 fi -if [[$UID != 0]]; then -echo Please run this script as root -exit 1 +if [[ $UID != 0 ]]; then + echo Please run this script as root + exit 1 fi apt update -y apt install python3 python3-pip git ffmpeg wget gnupg -y || exit 2 -su -c "python3 -m pip install -U pip" $SUDO_USER -su -c "python3 -m pip install -U wheel pillow" $SUDO_USER +su -c "python3 -m pip install -U pip" $SUDO_USER +su -c "python3 -m pip install -U wheel pillow" $SUDO_USER -if [[-d "Moon-Userbot"]]; then -cd Moon-Userbot -elif [[-f ".env.dist"]] && [[-f "main.py"]] && [[-d "modules"]]; then -: +if [[ -d "Moon-Userbot" ]]; then + cd Moon-Userbot +elif [[ -f ".env.dist" ]] && [[ -f "main.py" ]] && [[ -d "modules" ]]; then + : else - git clone https://github.com/The-MoonTg-project/Moon-Userbot || exit 2 -cd Moon-Userbot || exit 2 + git clone https://github.com/The-MoonTg-project/Moon-Userbot || exit 2 + cd Moon-Userbot || exit 2 fi -if [[-f ".env"]] && [[-f "my_account.session"]]; then -echo "It seems that Moon-Userbot is already installed. Exiting..." -exit +if [[ -f ".env" ]] && [[ -f "my_account.session" ]]; then + echo "It seems that Moon-Userbot is already installed. Exiting..." + exit fi -su -c "python3 -m pip install -U -r requirements.txt" $SUDO_USER || exit 2 +su -c "python3 -m pip install -U -r requirements.txt" $SUDO_USER || exit 2 echo -echo "Enter API_ID and API_HASH" -echo "You can get it here -> https://my.telegram.org/apps" -echo "Leave empty to use defaults (please note that default keys significantly increases your ban chances)" -read -r -p "API_ID > " api_id +echo "Enter API_ID and API_HASH" +echo "You can get it here -> https://my.telegram.org/" +echo "Leave empty to use defaults (please note that default keys significantly increases your ban chances)" +read -r -p "API_ID > " api_id -if [[$api_id = ""]]; then -api_id = "2040" -api_hash = "b18441a1ff607e10a989891a5462e627" +if [[ $api_id = "" ]]; then + api_id="2040" + api_hash="b18441a1ff607e10a989891a5462e627" else - read -r -p "API_HASH > " api_hash + read -r -p "API_HASH > " api_hash fi echo -echo "Choose database type:" -echo "[1] MongoDB db_url" -echo "[2] MongoDB localhost" -echo "[3] Sqlite (default)" -read -r -p "> " db_type +echo "Choose database type:" +echo "[1] MongoDB db_url" +echo "[2] MongoDB localhost" +echo "[3] Sqlite (default)" +read -r -p "> " db_type echo case $db_type in - 1) -echo "Please enter db_url" -echo "You can get it here -> " -read -r -p "> " db_url -db_name = Moon_Userbot -db_type = mongodb -;; -2) -if systemctl status mongodb; then -wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add - -source /etc/os-release -echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $ { -UBUNTU_CODENAME -}/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list -apt update -apt install mongodb -y -systemctl daemon-reload -systemctl enable mongodb -fi -systemctl start mongodb + 1) + echo "Please enter db_url" + echo "You can get it here -> https://mongodb.com/atlas" + read -r -p "> " db_url + db_name=Moon_Userbot + db_type=mongodb + ;; + 2) + if systemctl status mongodb; then + wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add - + source /etc/os-release + echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu ${UBUNTU_CODENAME}/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list + apt update + apt install mongodb -y + systemctl daemon-reload + systemctl enable mongodb + fi + systemctl start mongodb -db_url = mongodb://localhost:27017 -db_name = Moon_Userbot -db_type = mongodb -;; -*) -db_name = db.sqlite3 -db_type = sqlite3 -;; + db_url=mongodb://localhost:27017 + db_name=Moon_Userbot + db_type=mongodb + ;; + *) + db_name=db.sqlite3 + db_type=sqlite3 + ;; esac cat > .env << EOL - API_ID=${api_id} - API_HASH=${api_hash} - # sqlite/sqlite3 or mongo/mongodb - DATABASE_TYPE=${db_type} - # file name for sqlite3, database name for mongodb - DATABASE_NAME=${db_name} - # only for mongodb - DATABASE_URL=${db_url} - EOL - chown -R $SUDO_USER:$SUDO_USER . - echo - echo "Choose installation type:" - echo "[1] PM2" - echo "[2] Systemd service" - echo "[3] Custom (default)" - read -r -p "> " install_type - su -c "python3 install.py ${install_type}" $SUDO_USER || exit 3 - case $install_type in -   1) -     if ! command -v pm2; then -       curl -fsSL https://deb.nodesource.com/setup_17.x | bash -       apt install nodejs -y -       npm install pm2 -g -       su -c "pm2 startup" $SUDO_USER -       env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $SUDO_USER --hp /home/$SUDO_USER -     fi -     su -c "pm2 start main.py --name Moon --interpreter python3" $SUDO_USER -     su -c "pm2 save" $SUDO_USER -     echo -     echo "============================" -     echo "Great! Moon-Userbot installed successfully and running now!" -     echo "Installation type: PM2" -     echo "Start with: \"pm2 start Moon\"" -     echo "Stop with: \"pm2 stop Moon\"" -     echo "Process name: Moon" -     echo "============================" -     ;; -   2) -     cat > /etc/systemd/system/Moon.service << EOL - [Unit] - Description=Service for Moon Userbot - [Service] - Type=simple - ExecStart=$(which python3) ${PWD}/main.py - WorkingDirectory=${PWD} - Restart=always - User=${SUDO_USER} - Group=${SUDO_USER} - [Install] - WantedBy=multi-user.target - EOL -     systemctl daemon-reload -     systemctl start Moon -     systemctl enable Moon -     echo -     echo "============================" -     echo "Great! Moon-Userbot installed successfully and running now!" -     echo "Installation type: Systemd service" -     echo "Start with: \"sudo systemctl start Moon\"" -     echo "Stop with: \"sudo systemctl stop Moon\"" -     echo "============================" -     ;; -   *) -     echo -     echo "============================" -     echo "Great! Moon-Userbot installed successfully!" -     echo "Installation type: Custom" -     echo "Start with: \"python3 main.py\"" -     echo "============================" -     ;; - esac - chown -R $SUDO_USER:$SUDO_USER . \ No newline at end of file +API_ID=${api_id} +API_HASH=${api_hash} +# sqlite/sqlite3 or mongo/mongodb +DATABASE_TYPE=${db_type} +# file name for sqlite3, database name for mongodb +DATABASE_NAME=${db_name} +# only for mongodb +DATABASE_URL=${db_url} +EOL + +chown -R $SUDO_USER:$SUDO_USER . + +echo +echo "Choose installation type:" +echo "[1] PM2" +echo "[2] Systemd service" +echo "[3] Custom (default)" +read -r -p "> " install_type + +su -c "python3 install.py ${install_type}" $SUDO_USER || exit 3 + +case $install_type in + 1) + if ! command -v pm2; then + curl -fsSL https://deb.nodesource.com/setup_17.x | bash + apt install nodejs -y + npm install pm2 -g + su -c "pm2 startup" $SUDO_USER + env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $SUDO_USER --hp /home/$SUDO_USER + fi + su -c "pm2 start main.py --name Moon --interpreter python3" $SUDO_USER + su -c "pm2 save" $SUDO_USER + + echo + echo "============================" + echo "Great! Moon-Userbot installed successfully and running now!" + echo "Installation type: PM2" + echo "Start with: \"pm2 start Moon\"" + echo "Stop with: \"pm2 stop Moon\"" + echo "Process name: Moon" + echo "============================" + ;; + 2) + cat > /etc/systemd/system/Moon.service << EOL +[Unit] +Description=Service for Moon Userbot +[Service] +Type=simple +ExecStart=$(which python3) ${PWD}/main.py +WorkingDirectory=${PWD} +Restart=always +User=${SUDO_USER} +Group=${SUDO_USER} +[Install] +WantedBy=multi-user.target +EOL + systemctl daemon-reload + systemctl start Moon + systemctl enable Moon + + echo + echo "============================" + echo "Great! Moon-Userbot installed successfully and running now!" + echo "Installation type: Systemd service" + echo "Start with: \"sudo systemctl start Moon\"" + echo "Stop with: \"sudo systemctl stop Moon\"" + echo "============================" + ;; + *) + echo + echo "============================" + echo "Great! Moon-Userbot installed successfully!" + echo "Installation type: Custom" + echo "Start with: \"python3 main.py\"" + echo "============================" + ;; +esac + +chown -R $SUDO_USER:$SUDO_USER . \ No newline at end of file diff --git a/main.py b/main.py index f8e3b4d..82d885b 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,18 @@ -#  Moon-Userbot - telegram userbot -#  Copyright (C) 2020-present Moon Userbot Organization +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization # -#  This program is free software: you can redistribute it and/or modify -#  it is under the terms of the GNU General Public License as published by -#  the Free Software Foundation, either version 3 of the License, or -#  (at your option) any later version. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. -#  You should have received a copy of the GNU General Public License -#  along with this program.  If not, see . +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import sqlite3 import subprocess @@ -25,162 +25,135 @@ from importlib import import_module import logging import platform -logging.basicConfig(level = logging.INFO) +logging.basicConfig(level=logging.INFO) DeleteAccount.__new__ = None if __name__ == "__main__": -script_path = os.path.dirname(os.path.realpath(__file__)) -if script_path != os.getcwd(): -os.chdir(script_path) + script_path = os.path.dirname(os.path.realpath(__file__)) + if script_path != os.getcwd(): + os.chdir(script_path) -if os.path.exists("./config.ini.old") and not os.path.exists("./.env"): -logging.warning("Old config.ini file detected! Converting to .env...") -import configparser + if os.path.exists("./config.ini.old") and not os.path.exists("./.env"): + logging.warning("Old config.ini file detected! Converting to .env...") + import configparser -parser = configparser.ConfigParser() -parser.read("./config.ini.old") -db_url = parser.get("pyrogram", "db_url") -db_name = parser.get("db", "db_name") + parser = configparser.ConfigParser() + parser.read("./config.ini.old") + db_url = parser.get("pyrogram", "db_url") + db_name = parser.get("db", "db_name") -with open(".env.dist") as f: -env_text = f.read().format( - db_url = db_url, - db_name = db_name, - db_type = "mongodb", -) + with open(".env.dist") as f: + env_text = f.read().format( + db_url=db_url, + db_name=db_name, + db_type="mongodb", + ) -with open(".env", "w") as f: -f.write(env_text) + with open(".env", "w") as f: + f.write(env_text) -os.remove("./config.ini.old") + os.remove("./config.ini.old") -logging.warning("Old config file has been successfully converted") + logging.warning("Old config file has been successfully converted") -from utils.db import db -from utils.misc import gitrepo, userbot_version -from utils.scripts import restart -from utils import config + from utils.db import db + from utils.misc import gitrepo, userbot_version + from utils.scripts import restart + from utils import config -app = Client( - "my_account", - api_id = config.api_id, - api_hash = config.api_hash, - hide_password = True, - workdir = script_path, - app_version = userbot_version, - device_model = f"Moon-Userbot @  { - gitrepo.head.commit.hexsha[:7]}", - system_version = platform.version() + " " + platform.machine(), - sleep_threshold = 30, - test_mode = config.test_server, - parse_mode = "html", -) + app = Client( + "my_account", + api_id=config.api_id, + api_hash=config.api_hash, + hide_password=True, + workdir=script_path, + app_version=userbot_version, + device_model=f"Moon-Userbot @ {gitrepo.head.commit.hexsha[:7]}", + system_version=platform.version() + " " + platform.machine(), + sleep_threshold=30, + test_mode=config.test_server, + parse_mode="html", + ) -try: -app.start() -except sqlite3.OperationalError as e: -if str(e) == "database is locked" and os.name == "posix": -logging.warning( - "Session file is locked. Trying to kill blocking process..." -) -subprocess.run(["fuser", "-k", "my_account.session"]) -restart() -raise -except (errors.NotAcceptable, errors.Unauthorized) as e: -logging.error( -f" { - e.__class__.__name__ -}:  { - e -}\n" -f"Moving session file to my_account.session-old..." -) -os.rename("./my_account.session", "./my_account.session-old") -restart() + try: + app.start() + except sqlite3.OperationalError as e: + if str(e) == "database is locked" and os.name == "posix": + logging.warning( + "Session file is locked. Trying to kill blocking process..." + ) + subprocess.run(["fuser", "-k", "my_account.session"]) + restart() + raise + except (errors.NotAcceptable, errors.Unauthorized) as e: + logging.error( + f"{e.__class__.__name__}: {e}\n" + f"Moving session file to my_account.session-old..." + ) + os.rename("./my_account.session", "./my_account.session-old") + restart() -success_handlers = 0 -failed_handlers = 0 -success_modules = 0 -failed_modules = 0 + success_handlers = 0 + failed_handlers = 0 + success_modules = 0 + failed_modules = 0 -for path in sorted((Path("modules")).rglob("*.py")): -module_path = ".".join(path.parent.parts + (path.stem,)) -try: -module = import_module(module_path) -for name, obj in vars(module).items(): -# defaulting to [] if obj isn't a function-handler -for handler, group in getattr(obj, "handlers", []): -try: -app.add_handler(handler, group) -success_handlers += 1 -except Exception as e: -failed_handlers += 1 -logging.warning( -f"Can't add  { - module_path -}. { - name -}. { - handler.__name__ -}:  { - e.__class__.__name__ -}:  { - e -}" -) -except Exception as e: -logging.warning( -f"Can't import module  { - module_path -}:  { - e.__class__.__name__ -}:  { - e -}" -) -failed_modules += 1 -else : -success_modules += 1 + for path in sorted((Path("modules")).rglob("*.py")): + module_path = ".".join(path.parent.parts + (path.stem,)) + try: + module = import_module(module_path) + for name, obj in vars(module).items(): + # defaulting to [] if obj isn't a function-handler + for handler, group in getattr(obj, "handlers", []): + try: + app.add_handler(handler, group) + success_handlers += 1 + except Exception as e: + failed_handlers += 1 + logging.warning( + f"Can't add {module_path}.{name}.{handler.__name__}: {e.__class__.__name__}: {e}" + ) + except Exception as e: + logging.warning( + f"Can't import module {module_path}: {e.__class__.__name__}: {e}" + ) + failed_modules += 1 + else: + success_modules += 1 -logging.info( -f"Imported  { - success_handlers -} handlers from  { - success_modules -} modules." -) -if failed_modules: -logging.warning(f"Failed to import  { - failed_modules -} modules") -if failed_handlers: -logging.warning(f"Failed to add  { - failed_handlers -} to handlers") + logging.info( + f"Imported {success_handlers} handlers from {success_modules} modules." + ) + if failed_modules: + logging.warning(f"Failed to import {failed_modules} modules") + if failed_handlers: + logging.warning(f"Failed to add {failed_handlers} to handlers") -if len(sys.argv) == 4: -restart_type = sys.argv[3] -if restart_type == "1": -text = "Update process completed!" -else : -text = "Restart completed!" -try: -app.send_message( - chat_id = sys.argv[1], text = text, reply_to_message_id = int(sys.argv[2]) -) -except errors.RPCError: -app.send_message(chat_id = sys.argv[1], text = text) + if len(sys.argv) == 4: + restart_type = sys.argv[3] + if restart_type == "1": + text = "Update process completed!" + else: + text = "Restart completed!" + try: + app.send_message( + chat_id=sys.argv[1], text=text, reply_to_message_id=int( + sys.argv[2]) + ) + except errors.RPCError: + app.send_message(chat_id=sys.argv[1], text=text) -# required for sessionkiller module -if db.get("core.sessionkiller", "enabled", False): -db.set( - "core.sessionkiller", - "auths_hashes", - [auth.hash for auth in app.send(GetAuthorizations()).authorizations], -) + # required for sessionkiller module + if db.get("core.sessionkiller", "enabled", False): + db.set( + "core.sessionkiller", + "auths_hashes", + [auth.hash for auth in app.send( + GetAuthorizations()).authorizations], + ) -logging.info("Moon-Userbot started!") + logging.info("Moon-Userbot started!") -idle() \ No newline at end of file + idle() diff --git a/modules/admintool.py b/modules/admintool.py index c68ccf3..951cfe5 100644 --- a/modules/admintool.py +++ b/modules/admintool.py @@ -1,1256 +1,1267 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - import re - from time import time - from typing import Dict, Union - from contextlib import suppress - - from pyrogram import Client, ContinuePropagation, filters - from pyrogram.errors import ( -     UserAdminInvalid, -     ChatAdminRequired, -     PeerIdInvalid, -     UsernameInvalid, -     RPCError, - ) - from pyrogram.raw import functions, types - from pyrogram.types import Message, ChatPermissions - from pyrogram.utils import ( -     get_channel_id, -     MAX_USER_ID, -     MIN_CHAT_ID, -     MAX_CHANNEL_ID, -     MIN_CHANNEL_ID, - ) - - from utils.db import db - from utils.scripts import text, format_exc, with_reply - from utils.misc import modules_help, prefix - - - db_cache: dict = db.get_collection("core.ats") - - - def update_cache(): -     db_cache.clear() -     db_cache.update(db.get_collection("core.ats")) - - - @Client.on_message(filters.group & ~filters.edited & ~filters.me) - async def admintool_handler(_, message: Message): -     if message.sender_chat: -         if ( -             message.sender_chat.type == "supergroup" -             or message.sender_chat.id == db_cache.get(f"linked{message.chat.id}", 0) -         ): -             raise ContinuePropagation - -     if message.sender_chat and db_cache.get(f"antich{message.chat.id}", False): -         with suppress(RPCError): -             await message.delete() -             await message.chat.ban_member(message.sender_chat.id) - -     tmuted_users = db_cache.get(f"c{message.chat.id}", []) -     if ( -         message.from_user -         and message.from_user.id in tmuted_users -         or message.sender_chat -         and message.sender_chat.id in tmuted_users -     ): -         with suppress(RPCError): -             await message.delete() - -     if db_cache.get(f"antiraid{message.chat.id}", False): -         with suppress(RPCError): -             await message.delete() -             if message.from_user: -                 await message.chat.ban_member(message.from_user.id) -             elif message.sender_chat: -                 await message.chat.ban_member(message.sender_chat.id) - -     if message.new_chat_members: -         if db_cache.get(f"welcome_enabled{message.chat.id}", False): -             await message.reply( -                 db_cache.get(f"welcome_text{message.chat.id}"), -                 disable_web_page_preview=True, -             ) - -     raise ContinuePropagation - - - async def check_username_or_id(data: Union[str, int]) -> str: -     data = str(data) -     if ( -         not data.isdigit() -         and data[0] == "-" -         and not data[1:].isdigit() -         or not data.isdigit() -         and data[0] != "-" -     ): -         return "channel" -     else: -         peer_id = int(data) -     if peer_id < 0: -         if MIN_CHAT_ID <= peer_id: -             return "chat" - -         if MIN_CHANNEL_ID <= peer_id < MAX_CHANNEL_ID: -             return "channel" -     elif 0 < peer_id <= MAX_USER_ID: -         return "user" - -     raise ValueError(f"Peer id invalid: {peer_id}") - - - async def get_user_and_name(message): -     if message.reply_to_message.from_user: -         return ( -             message.reply_to_message.from_user.id, -             message.reply_to_message.from_user.first_name, -         ) -     elif message.reply_to_message.sender_chat: -         return ( -             message.reply_to_message.sender_chat.id, -             message.reply_to_message.sender_chat.title, -         ) - - - @Client.on_message(filters.command(["ban"], prefix) & filters.me) - async def ban_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         user_for_ban, name = await get_user_and_name(message) -         try: -             await client.ban_chat_member(message.chat.id, user_for_ban) -             channel = await client.resolve_peer(message.chat.id) -             user_id = await client.resolve_peer(user_for_ban) -             if "report_spam" in cause.lower().split(): -                 await client.send( -                     functions.channels.ReportSpam( -                         channel=channel, -                         participant=user_id, -                         id=[message.reply_to_message.message_id], -                     ) -                 ) -             if "delete_history" in cause.lower().split(): -                 await client.send( -                     functions.channels.DeleteParticipantHistory( -                         channel=channel, participant=user_id -                     ) -                 ) -             text_c = "".join( -                 f" {_}" -                 for _ in cause.split() -                 if _.lower() not in ["delete_history", "report_spam"] -             ) - -             await message.edit( -                 f"{name} banned!" -                 + f"\n{'Cause: ' + text_c.split(maxsplit=1)[1] + '' if len(text_c.split()) > 1 else ''}" -             ) -         except UserAdminInvalid: -             await message.edit("No rights") -         except ChatAdminRequired: -             await message.edit("No rights") -         except Exception as e: -             await message.edit(format_exc(e)) -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 if await check_username_or_id(cause.split(" ")[1]) == "channel": -                     user_to_ban = await client.get_chat(cause.split(" ")[1]) -                 elif await check_username_or_id(cause.split(" ")[1]) == "user": -                     user_to_ban = await client.get_users(cause.split(" ")[1]) -                 else: -                     await message.edit("Invalid user type") -                     return - -                 name = ( -                     user_to_ban.first_name -                     if getattr(user_to_ban, "first_name", None) -                     else user_to_ban.title -                 ) - -                 try: -                     channel = await client.resolve_peer(message.chat.id) -                     user_id = await client.resolve_peer(user_to_ban.id) -                     if ( -                         "report_spam" in cause.lower().split() -                         and message.reply_to_message -                     ): -                         await client.send( -                             functions.channels.ReportSpam( -                                 channel=channel, -                                 participant=user_id, -                                 id=[message.reply_to_message.message_id], -                             ) -                         ) -                     if "delete_history" in cause.lower().split(): -                         await client.send( -                             functions.channels.DeleteParticipantHistory( -                                 channel=channel, participant=user_id -                             ) -                         ) - -                     text_c = "".join( -                         f" {_}" -                         for _ in cause.split() -                         if _.lower() not in ["delete_history", "report_spam"] -                     ) - -                     await client.ban_chat_member(message.chat.id, user_to_ban.id) -                     await message.edit( -                         f"{name} banned!" -                         + f"\n{'Cause: ' + text_c.split(' ', maxsplit=2)[2] + '' if len(text_c.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["unban"], prefix) & filters.me) - async def unban_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         user_for_unban, name = await get_user_and_name(message) -         try: -             await client.unban_chat_member(message.chat.id, user_for_unban) -             await message.edit( -                 f"{name} unbanned!" -                 + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -             ) -         except UserAdminInvalid: -             await message.edit("No rights") -         except ChatAdminRequired: -             await message.edit("No rights") -         except Exception as e: -             await message.edit(format_exc(e)) - -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 if await check_username_or_id(cause.split(" ")[1]) == "channel": -                     user_to_unban = await client.get_chat(cause.split(" ")[1]) -                 elif await check_username_or_id(cause.split(" ")[1]) == "user": -                     user_to_unban = await client.get_users(cause.split(" ")[1]) -                 else: -                     await message.edit("Invalid user type") -                     return - -                 name = ( -                     user_to_unban.first_name -                     if getattr(user_to_unban, "first_name", None) -                     else user_to_unban.title -                 ) - -                 try: -                     await client.unban_chat_member(message.chat.id, user_to_unban.id) -                     await message.edit( -                         f"{name} unbanned!" -                         + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["kick"], prefix) & filters.me) - async def kick_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         if message.reply_to_message.from_user: -             try: -                 await client.ban_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     int(time() + 60), -                 ) -                 channel = await client.resolve_peer(message.chat.id) -                 user_id = await client.resolve_peer( -                     message.reply_to_message.from_user.id -                 ) -                 if "report_spam" in cause.lower().split() and message.reply_to_message: -                     await client.send( -                         functions.channels.ReportSpam( -                             channel=channel, -                             participant=user_id, -                             id=[message.reply_to_message.message_id], -                         ) -                     ) -                 if "delete_history" in cause.lower().split(): -                     await client.send( -                         functions.channels.DeleteParticipantHistory( -                             channel=channel, participant=user_id -                         ) -                     ) -                 text_c = "".join( -                     f" {_}" -                     for _ in cause.split() -                     if _.lower() not in ["delete_history", "report_spam"] -                 ) - -                 await message.edit( -                     f"{message.reply_to_message.from_user.first_name} kicked!" -                     + f"\n{'Cause: ' + text_c.split(maxsplit=1)[1] + '' if len(text_c.split()) > 1 else ''}" -                 ) -             except UserAdminInvalid: -                 await message.edit("No rights") -             except ChatAdminRequired: -                 await message.edit("No rights") -             except Exception as e: -                 await message.edit(format_exc(e)) -         else: -             await message.edit("Reply on user msg") -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 user_to_ban = await client.get_users(cause.split(" ")[1]) -                 try: -                     channel = await client.resolve_peer(message.chat.id) -                     user_id = await client.resolve_peer(user_to_ban.id) -                     if ( -                         "report_spam" in cause.lower().split() -                         and message.reply_to_message -                     ): -                         await client.send( -                             functions.channels.ReportSpam( -                                 channel=channel, -                                 participant=user_id, -                                 id=[message.reply_to_message.message_id], -                             ) -                         ) -                     if "delete_history" in cause.lower().split(): -                         await client.send( -                             functions.channels.DeleteParticipantHistory( -                                 channel=channel, participant=user_id -                             ) -                         ) - -                     text_c = "".join( -                         f" {_}" -                         for _ in cause.split() -                         if _.lower() not in ["delete_history", "report_spam"] -                     ) - -                     await client.ban_chat_member( -                         message.chat.id, user_to_ban.id, int(time() + 60) -                     ) -                     await message.edit( -                         f"{user_to_ban.first_name} kicked!" -                         + f"\n{'Cause: ' + text_c.split(' ', maxsplit=2)[2] + '' if len(text_c.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["kickdel"], prefix) & filters.me) - async def kickdel_cmd(_, message: Message): -     await message.edit("Kicking deleted accounts...") -     # noinspection PyTypeChecker -     values = [ -         await message.chat.ban_member(user.user.id, int(time()) + 31) -         for member in await message.chat.get_members() -         if member.user.is_deleted -     ] -     await message.edit(f"Successfully kicked {len(values)} deleted account(s)") - - - @Client.on_message(filters.command(["tmute"], prefix) & filters.me) - async def tmute_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         user_for_tmute, name = await get_user_and_name(message) - -         if ( -             message.reply_to_message.from_user -             and message.reply_to_message.from_user.is_self -         ): -             return await message.edit("Not on yourself") - -         tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) -         if user_for_tmute not in tmuted_users: -             tmuted_users.append(user_for_tmute) -             db.set("core.ats", f"c{message.chat.id}", tmuted_users) -             await message.edit( -                 f"{name} in tmute" -                 + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -             ) -         else: -             await message.edit(f"{name} already in tmute") - -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 if await check_username_or_id(cause.split(" ")[1]) == "channel": -                     user_to_tmute = await client.get_chat(cause.split(" ")[1]) -                 elif await check_username_or_id(cause.split(" ")[1]) == "user": -                     user_to_tmute = await client.get_users(cause.split(" ")[1]) -                     if user_to_tmute.is_self: -                         return await message.edit("Not on yourself") -                 else: -                     await message.edit("Invalid user type") -                     return - -                 name = ( -                     user_to_tmute.first_name -                     if getattr(user_to_tmute, "first_name", None) -                     else user_to_tmute.title -                 ) - -                 tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) -                 if user_to_tmute.id not in tmuted_users: -                     tmuted_users.append(user_to_tmute.id) -                     db.set("core.ats", f"c{message.chat.id}", tmuted_users) -                     await message.edit( -                         f"{name} in tmute" -                         + f"\n{'Cause: ' + cause.split(maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 else: -                     await message.edit(f"{name} already in tmute") - -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - -     update_cache() - - - @Client.on_message(filters.command(["tunmute"], prefix) & filters.me) - async def tunmute_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         user_for_tunmute, name = await get_user_and_name(message) - -         tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) -         if user_for_tunmute not in tmuted_users: -             await message.edit(f"{name} not in tmute") -         else: -             tmuted_users.remove(user_for_tunmute) -             db.set("core.ats", f"c{message.chat.id}", tmuted_users) -             await message.edit( -                 f"{name} tunmuted" -                 + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -             ) - -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 if await check_username_or_id(cause.split(" ")[1]) == "channel": -                     user_to_tunmute = await client.get_chat(cause.split(" ")[1]) -                 elif await check_username_or_id(cause.split(" ")[1]) == "user": -                     user_to_tunmute = await client.get_users(cause.split(" ")[1]) -                     if user_to_tunmute.is_self: -                         return await message.edit("Not on yourself") -                 else: -                     await message.edit("Invalid user type") -                     return - -                 name = ( -                     user_to_tunmute.first_name -                     if getattr(user_to_tunmute, "first_name", None) -                     else user_to_tunmute.title -                 ) - -                 tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) -                 if user_to_tunmute.id not in tmuted_users: -                     await message.edit(f"{name} not in tmute") -                 else: -                     tmuted_users.remove(user_to_tunmute.id) -                     db.set("core.ats", f"c{message.chat.id}", tmuted_users) -                     await message.edit( -                         f"{name} tunmuted" -                         + f"\n{'Cause: ' + cause.split(maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - -     update_cache() - - - @Client.on_message(filters.command(["tmute_users"], prefix) & filters.me) - async def tunmute_users_command(client: Client, message: Message): -     if message.chat.type not in ["private", "channel"]: -         text = f"All users {message.chat.title} who are now in tmute\n\n" -         count = 0 -         tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) -         for user in tmuted_users: -             try: -                 _name_ = await client.get_chat(user) -                 count += 1 -                 if await check_username_or_id(_name_.id) == "channel": -                     channel = await client.send( -                         functions.channels.GetChannels( -                             id=[ -                                 types.InputChannel( -                                     channel_id=get_channel_id(_name_.id), -                                     access_hash=0, -                                 ) -                             ] -                         ) -                     ) -                     name = channel.chats[0].title -                 elif await check_username_or_id(_name_.id) == "user": -                     user = await client.get_users(_name_.id) -                     name = user.first_name -                 else: -                     # invalid user type -                     continue -                 text += f"{count}. {name}\n" -             except PeerIdInvalid: -                 pass -         if count == 0: -             await message.edit("No users in tmute") -         else: -             text += f"\nTotal users in tmute {count}" -             await message.edit(text) -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["unmute"], prefix) & filters.me) - async def unmute_command(client, message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         u_p = message.chat.permissions -         if message.reply_to_message.from_user: -             try: -                 await client.restrict_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     u_p, -                     int(time() + 30), -                 ) -                 await message.edit( -                     f"{message.reply_to_message.from_user.first_name} unmuted" -                     + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -                 ) -             except UserAdminInvalid: -                 await message.edit("No rights") -             except ChatAdminRequired: -                 await message.edit("No rights") -             except Exception as e: -                 await message.edit(format_exc(e)) -         else: -             await message.edit("Reply on user msg") -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         u_p = message.chat.permissions -         if len(cause.split()) > 1: -             try: -                 user_to_unmute = await client.get_users(cause.split(" ")[1]) -                 try: -                     await client.restrict_chat_member( -                         message.chat.id, user_to_unmute.id, u_p, int(time() + 30) -                     ) -                     await message.edit( -                         f"{user_to_unmute.first_name} unmuted!" -                         + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["mute"], prefix) & filters.me) - async def mute_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         mute_seconds: int = 0 -         for character in "mhdw": -             match = re.search(rf"(\d+|(\d+\.\d+)){character}", message.text) -             if match: -                 if character == "m": -                     mute_seconds += int( -                         float(match.string[match.start() : match.end() - 1]) * 60 // 1 -                     ) -                 if character == "h": -                     mute_seconds += int( -                         float(match.string[match.start() : match.end() - 1]) * 3600 // 1 -                     ) -                 if character == "d": -                     mute_seconds += int( -                         float(match.string[match.start() : match.end() - 1]) -                         * 86400 -                         // 1 -                     ) -                 if character == "w": -                     mute_seconds += int( -                         float(match.string[match.start() : match.end() - 1]) -                         * 604800 -                         // 1 -                     ) -         try: -             if mute_seconds > 30: -                 await client.restrict_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     ChatPermissions(), -                     int(time()) + mute_seconds, -                 ) -                 from_user = message.reply_to_message.from_user -                 mute_time: Dict[str, int] = { -                     "days": mute_seconds // 86400, -                     "hours": mute_seconds % 86400 // 3600, -                     "minutes": mute_seconds % 86400 % 3600 // 60, -                 } -                 message_text = ( -                     f"{from_user.first_name}  was muted for" -                     f" {((str(mute_time['days']) + ' day') if mute_time['days'] > 0 else '') + ('s' if mute_time['days'] > 1 else '')}" -                     f" {((str(mute_time['hours']) + ' hour') if mute_time['hours'] > 0 else '') + ('s' if mute_time['hours'] > 1 else '')}" -                     f" {((str(mute_time['minutes']) + ' minute') if mute_time['minutes'] > 0 else '') + ('s' if mute_time['minutes'] > 1 else '')}" -                     + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                 ) -                 while "  " in message_text: -                     message_text = message_text.replace("  ", " ") -             else: -                 await client.restrict_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     ChatPermissions(), -                 ) -                 message_text = ( -                     f"{message.reply_to_message.from_user.first_name}  was muted indefinitely" -                     + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -                 ) -             await message.edit(message_text) -         except UserAdminInvalid: -             await message.edit("No rights") -         except ChatAdminRequired: -             await message.edit("No rights") -         except Exception as e: -             await message.edit(format_exc(e)) -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 user_to_unmute = await client.get_users(cause.split(" ")[1]) -                 mute_seconds: int = 0 -                 for character in "mhdw": -                     match = re.search(rf"(\d+|(\d+\.\d+)){character}", message.text) -                     if match: -                         if character == "m": -                             mute_seconds += int( -                                 float(match.string[match.start() : match.end() - 1]) -                                 * 60 -                                 // 1 -                             ) -                         if character == "h": -                             mute_seconds += int( -                                 float(match.string[match.start() : match.end() - 1]) -                                 * 3600 -                                 // 1 -                             ) -                         if character == "d": -                             mute_seconds += int( -                                 float(match.string[match.start() : match.end() - 1]) -                                 * 86400 -                                 // 1 -                             ) -                         if character == "w": -                             mute_seconds += int( -                                 float(match.string[match.start() : match.end() - 1]) -                                 * 604800 -                                 // 1 -                             ) -                 try: -                     if mute_seconds > 30: -                         await client.restrict_chat_member( -                             message.chat.id, -                             user_to_unmute.id, -                             ChatPermissions(), -                             int(time()) + mute_seconds, -                         ) -                         mute_time: Dict[str, int] = { -                             "days": mute_seconds // 86400, -                             "hours": mute_seconds % 86400 // 3600, -                             "minutes": mute_seconds % 86400 % 3600 // 60, -                         } -                         message_text = ( -                             f"{user_to_unmute.first_name}  was muted for" -                             f" {((str(mute_time['days']) + ' day') if mute_time['days'] > 0 else '') + ('s' if mute_time['days'] > 1 else '')}" -                             f" {((str(mute_time['hours']) + ' hour') if mute_time['hours'] > 0 else '') + ('s' if mute_time['hours'] > 1 else '')}" -                             f" {((str(mute_time['minutes']) + ' minute') if mute_time['minutes'] > 0 else '') + ('s' if mute_time['minutes'] > 1 else '')}" -                             + f"\n{'Cause: ' + cause.split(' ', maxsplit=3)[3] + '' if len(cause.split()) > 3 else ''}" -                         ) -                         while "  " in message_text: -                             message_text = message_text.replace("  ", " ") -                     else: -                         await client.restrict_chat_member( -                             message.chat.id, user_to_unmute.id, ChatPermissions() -                         ) -                         message_text = ( -                             f"{user_to_unmute.first_name}  was muted indefinitely" -                             + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                         ) -                     await message.edit(message_text) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["demote"], prefix) & filters.me) - async def demote_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         if message.reply_to_message.from_user: -             try: -                 await client.promote_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     is_anonymous=False, -                     can_manage_chat=False, -                     can_change_info=False, -                     can_post_messages=False, -                     can_edit_messages=False, -                     can_delete_messages=False, -                     can_restrict_members=False, -                     can_invite_users=False, -                     can_pin_messages=False, -                     can_promote_members=False, -                     can_manage_voice_chats=False, -                 ) -                 await message.edit( -                     f"{message.reply_to_message.from_user.first_name} demoted!" -                     + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -                 ) -             except UserAdminInvalid: -                 await message.edit("No rights") -             except ChatAdminRequired: -                 await message.edit("No rights") -             except Exception as e: -                 await message.edit(format_exc(e)) -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 promote_user = await client.get_users(cause.split(" ")[1]) -                 try: -                     await client.promote_chat_member( -                         message.chat.id, -                         promote_user.id, -                         is_anonymous=False, -                         can_manage_chat=False, -                         can_change_info=False, -                         can_post_messages=False, -                         can_edit_messages=False, -                         can_delete_messages=False, -                         can_restrict_members=False, -                         can_invite_users=False, -                         can_pin_messages=False, -                         can_promote_members=False, -                         can_manage_voice_chats=False, -                     ) -                     await message.edit( -                         f"{promote_user.first_name} demoted!" -                         + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["promote"], prefix) & filters.me) - async def promote_command(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         if message.reply_to_message.from_user: -             try: -                 await client.promote_chat_member( -                     message.chat.id, -                     message.reply_to_message.from_user.id, -                     can_delete_messages=True, -                     can_restrict_members=True, -                     can_invite_users=True, -                     can_pin_messages=True, -                 ) -                 if len(cause.split()) > 1: -                     await client.set_administrator_title( -                         message.chat.id, -                         message.reply_to_message.from_user.id, -                         cause.split(maxsplit=1)[1], -                     ) -                 await message.edit( -                     f"{message.reply_to_message.from_user.first_name} promoted!" -                     + f"\n{'Prefix: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -                 ) -             except UserAdminInvalid: -                 await message.edit("No rights") -             except ChatAdminRequired: -                 await message.edit("No rights") -             except Exception as e: -                 await message.edit(format_exc(e)) -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 promote_user = await client.get_users(cause.split(" ")[1]) -                 try: -                     await client.promote_chat_member( -                         message.chat.id, -                         promote_user.id, -                         can_delete_messages=True, -                         can_restrict_members=True, -                         can_invite_users=True, -                         can_pin_messages=True, -                     ) -                     if len(cause.split()) > 1: -                         await client.set_administrator_title( -                             message.chat.id, -                             promote_user.id, -                             f"\n{cause.split(' ', maxsplit=2)[2] if len(cause.split()) > 2 else None}", -                         ) -                     await message.edit( -                         f"{promote_user.first_name} promoted!" -                         + f"\n{'Prefix: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["antich"], prefix)) - async def anti_channels(client: Client, message: Message): -     if message.chat.type != "supergroup": -         await message.edit("Not supported in non-supergroup chats") -         return - -     if len(message.command) == 1: -         if db.get("core.ats", f"antich{message.chat.id}", False): -             await message.edit( -                 "Blocking channels in this chat is enabled.\n" -                 f"Disable with: {prefix}antich disable" -             ) -         else: -             await message.edit( -                 "Blocking channels in this chat is disabled.\n" -                 f"Enable with: {prefix}antich enable" -             ) -     elif message.command[1] in ["enable", "on", "1", "yes", "true"]: -         db.set("core.ats", f"antich{message.chat.id}", True) -         group = await client.get_chat(message.chat.id) -         if group.linked_chat: -             db.set("core.ats", f"linked{message.chat.id}", group.linked_chat.id) -         else: -             db.set("core.ats", f"linked{message.chat.id}", 0) -         await message.edit("Blocking channels in this chat enabled.") -     elif message.command[1] in ["disable", "off", "0", "no", "false"]: -         db.set("core.ats", f"antich{message.chat.id}", False) -         await message.edit("Blocking channels in this chat disabled.") -     else: -         await message.edit(f"Usage: {prefix}antich [enable|disable]") - -     update_cache() - - - @Client.on_message(filters.command(["delete_history", "dh"], prefix)) - async def delete_history(client: Client, message: Message): -     cause = text(message) -     if message.reply_to_message and message.chat.type not in ["private", "channel"]: -         if message.reply_to_message.from_user: -             try: -                 user_for_delete, name = await get_user_and_name(message) -                 channel = await client.resolve_peer(message.chat.id) -                 user_id = await client.resolve_peer(user_for_delete) -                 await client.send( -                     functions.channels.DeleteParticipantHistory( -                         channel=channel, participant=user_id -                     ) -                 ) - -                 await message.edit( -                     f"History from {name} was deleted!" -                     + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" -                 ) -             except UserAdminInvalid: -                 await message.edit("No rights") -             except ChatAdminRequired: -                 await message.edit("No rights") -             except Exception as e: -                 await message.edit(format_exc(e)) -         else: -             await message.edit("Reply on user msg") -     elif not message.reply_to_message and message.chat.type not in [ -         "private", -         "channel", -     ]: -         if len(cause.split()) > 1: -             try: -                 if await check_username_or_id(cause.split(" ")[1]) == "channel": -                     user_to_delete = await client.get_chat(cause.split(" ")[1]) -                 elif await check_username_or_id(cause.split(" ")[1]) == "user": -                     user_to_delete = await client.get_users(cause.split(" ")[1]) -                 else: -                     await message.edit("Invalid user type") -                     return - -                 name = ( -                     user_to_delete.first_name -                     if getattr(user_to_delete, "first_name", None) -                     else user_to_delete.title -                 ) - -                 try: -                     channel = await client.resolve_peer(message.chat.id) -                     user_id = await client.resolve_peer(user_to_delete.id) -                     await client.send( -                         functions.channels.DeleteParticipantHistory( -                             channel=channel, participant=user_id -                         ) -                     ) -                     await message.edit( -                         f"History from {name} was deleted!" -                         + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" -                     ) -                 except UserAdminInvalid: -                     await message.edit("No rights") -                 except ChatAdminRequired: -                     await message.edit("No rights") -                 except Exception as e: -                     await message.edit(format_exc(e)) -             except PeerIdInvalid: -                 await message.edit("User is not found") -             except UsernameInvalid: -                 await message.edit("User is not found") -             except IndexError: -                 await message.edit("User is not found") -         else: -             await message.edit("user_id or username") -     else: -         await message.edit("Unsupported") - - - @Client.on_message(filters.command(["report_spam", "rs"], prefix)) - @with_reply - async def report_spam(client: Client, message: Message): -     try: -         channel = await client.resolve_peer(message.chat.id) - -         user_id, name = await get_user_and_name(message) -         peer = await client.resolve_peer(user_id) -         await client.send( -             functions.channels.ReportSpam( -                 channel=channel, -                 participant=peer, -                 id=[message.reply_to_message.message_id], -             ) -         ) -     except Exception as e: -         await message.edit(format_exc(e)) -     else: -         await message.edit(f"Message from {name} was reported") - - - @Client.on_message(filters.command("pin", prefix) & filters.me) - @with_reply - async def pin(_, message: Message): -     try: -         await message.reply_to_message.pin() -         await message.edit("Pinned!") -     except Exception as e: -         await message.edit(format_exc(e)) - - - @Client.on_message(filters.command("unpin", prefix) & filters.me) - @with_reply - async def unpin(_, message: Message): -     try: -         await message.reply_to_message.unpin() -         await message.edit("Unpinned!") -     except Exception as e: -         await message.edit(format_exc(e)) - - - @Client.on_message(filters.command("ro", prefix) & filters.me) - async def ro(client: Client, message: Message): -     if message.chat.type != "supergroup": -         await message.edit("Invalid chat type") -         return - -     try: -         perms = message.chat.permissions -         perms_list = [ -             perms.can_send_messages, -             perms.can_send_media_messages, -             perms.can_send_other_messages, -             perms.can_send_polls, -             perms.can_add_web_page_previews, -             perms.can_change_info, -             perms.can_invite_users, -             perms.can_pin_messages, -         ] -         db.set("core.ats", f"ro{message.chat.id}", perms_list) - -         try: -             await client.set_chat_permissions(message.chat.id, ChatPermissions()) -         except (UserAdminInvalid, ChatAdminRequired): -             await message.edit("No rights") -         else: -             await message.edit( -                 "Read-only mode activated!\n" -                 f"Turn off with:{prefix}unro" -             ) -     except Exception as e: -         await message.edit(format_exc(e)) - - - @Client.on_message(filters.command("unro", prefix) & filters.me) - async def unro(client: Client, message: Message): -     if message.chat.type != "supergroup": -         await message.edit("Invalid chat type") -         return - -     try: -         perms_list = db.get( -             "core.ats", -             f"ro{message.chat.id}", -             [True, True, True, False, False, False, False, False], -         ) -         perms = ChatPermissions( -             can_send_messages=perms_list[0], -             can_send_media_messages=perms_list[1], -             can_send_other_messages=perms_list[2], -             can_send_polls=perms_list[3], -             can_add_web_page_previews=perms_list[4], -             can_change_info=perms_list[5], -             can_invite_users=perms_list[6], -             can_pin_messages=perms_list[7], -         ) - -         try: -             await client.set_chat_permissions(message.chat.id, perms) -         except (UserAdminInvalid, ChatAdminRequired): -             await message.edit("No rights") -         else: -             await message.edit("Read-only mode disabled!") -     except Exception as e: -         await message.edit(format_exc(e)) - - - @Client.on_message(filters.command("antiraid", prefix) & filters.me) - async def antiraid(client: Client, message: Message): -     if message.chat.type != "supergroup": -         await message.edit("Not supported in non-supergroup chats") -         return - -     if len(message.command) > 1 and message.command[1] == "on": -         db.set("core.ats", f"antiraid{message.chat.id}", True) -         group = await client.get_chat(message.chat.id) -         if group.linked_chat: -             db.set("core.ats", f"linked{message.chat.id}", group.linked_chat.id) -         else: -             db.set("core.ats", f"linked{message.chat.id}", 0) -         await message.edit( -             "Anti-raid mode enabled!\n" -             f"Disable with: {prefix}antiraid off" -         ) -     elif len(message.command) > 1 and message.command[1] == "off": -         db.set("core.ats", f"antiraid{message.chat.id}", False) -         await message.edit("Anti-raid mode disabled") -     else: -         # toggle -         if db.get("core.ats", f"antiraid{message.chat.id}", False): -             db.set("core.ats", f"antiraid{message.chat.id}", False) -             await message.edit("Anti-raid mode disabled") -         else: -             db.set("core.ats", f"antiraid{message.chat.id}", True) -             group = await client.get_chat(message.chat.id) -             if group.linked_chat: -                 db.set("core.ats", f"linked{message.chat.id}", group.linked_chat.id) -             else: -                 db.set("core.ats", f"linked{message.chat.id}", 0) -             await message.edit( -                 "Anti-raid mode enabled!\n" -                 f"Disable with: {prefix}antiraid off" -             ) - -     update_cache() - - - @Client.on_message(filters.command(["welcome", "wc"], prefix) & filters.me) - async def welcome(_, message: Message): -     if message.chat.type != "supergroup": -         return await message.edit("Unsupported chat type") - -     if len(message.command) > 1: -         text = message.text.split(maxsplit=1)[1] -         db.set("core.ats", f"welcome_enabled{message.chat.id}", True) -         db.set("core.ats", f"welcome_text{message.chat.id}", text) - -         await message.edit( -             f"Welcome enabled in this chat\nText: {text}" -         ) -     else: -         db.set("core.ats", f"welcome_enabled{message.chat.id}", False) -         await message.edit("Welcome disabled in this chat") - -     update_cache() - - - modules_help["admintool"] = { -     "ban [reply]/[username/id]* [reason] [report_spam] [delete_history]": "ban user in chat", -     "unban [reply]/[username/id]* [reason]": "unban user in chat", -     "kick [reply]/[userid]* [reason] [report_spam] [delete_history]": "kick user out of chat", -     "mute [reply]/[userid]* [reason] [1m]/[1h]/[1d]/[1w]": "mute user in chat", -     "unmute [reply]/[userid]* [reason]": "unmute user in chat", -     "promote [reply]/[userid]* [prefix]": "promote user in chat", -     "demote [reply]/[userid]* [reason]": "demote user in chat", -     "tmute [reply]/[username/id]* [reason]": "delete all new messages from user in chat", -     "tunmute [reply]/[username/id]* [reason]": "stop deleting all messages from user in chat", -     "tmute_users": "list of tmuted (.tmute) users", -     "antich [enable/disable]": "turn on/off blocking channels in this chat", -     "delete_history [reply]/[username/id]* [reason]": "delete history from member in chat", -     "report_spam [reply]*": "report spam message in chat", -     "pin [reply]*": "Pin replied message", -     "unpin [reply]*": "Unpin replied message", -     "ro": "enable read-only mode", -     "unro": "disable read-only mode", -     "antiraid [on|off]": "when enabled, anyone who writes message will be blocked. Useful in raids. " -     "Running without arguments equals to toggling state", -     "welcome [text]*": "enable auto-welcome to new users in groups. " -     "Running without text equals to disable", -     "kickdel": "Kick all deleted accounts", - } \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import re +from time import time +from typing import Dict, Union +from contextlib import suppress + +from pyrogram import Client, ContinuePropagation, filters +from pyrogram.errors import ( + UserAdminInvalid, + ChatAdminRequired, + PeerIdInvalid, + UsernameInvalid, + RPCError, +) +from pyrogram.raw import functions, types +from pyrogram.types import Message, ChatPermissions +from pyrogram.utils import ( + get_channel_id, + MAX_USER_ID, + MIN_CHAT_ID, + MAX_CHANNEL_ID, + MIN_CHANNEL_ID, +) + +from utils.db import db +from utils.scripts import text, format_exc, with_reply +from utils.misc import modules_help, prefix + + +db_cache: dict = db.get_collection("core.ats") + + +def update_cache(): + db_cache.clear() + db_cache.update(db.get_collection("core.ats")) + + +@Client.on_message(filters.group & ~filters.edited & ~filters.me) +async def admintool_handler(_, message: Message): + if message.sender_chat: + if ( + message.sender_chat.type == "supergroup" + or message.sender_chat.id == db_cache.get(f"linked{message.chat.id}", 0) + ): + raise ContinuePropagation + + if message.sender_chat and db_cache.get(f"antich{message.chat.id}", False): + with suppress(RPCError): + await message.delete() + await message.chat.ban_member(message.sender_chat.id) + + tmuted_users = db_cache.get(f"c{message.chat.id}", []) + if ( + message.from_user + and message.from_user.id in tmuted_users + or message.sender_chat + and message.sender_chat.id in tmuted_users + ): + with suppress(RPCError): + await message.delete() + + if db_cache.get(f"antiraid{message.chat.id}", False): + with suppress(RPCError): + await message.delete() + if message.from_user: + await message.chat.ban_member(message.from_user.id) + elif message.sender_chat: + await message.chat.ban_member(message.sender_chat.id) + + if message.new_chat_members: + if db_cache.get(f"welcome_enabled{message.chat.id}", False): + await message.reply( + db_cache.get(f"welcome_text{message.chat.id}"), + disable_web_page_preview=True, + ) + + raise ContinuePropagation + + +async def check_username_or_id(data: Union[str, int]) -> str: + data = str(data) + if ( + not data.isdigit() + and data[0] == "-" + and not data[1:].isdigit() + or not data.isdigit() + and data[0] != "-" + ): + return "channel" + else: + peer_id = int(data) + if peer_id < 0: + if MIN_CHAT_ID <= peer_id: + return "chat" + + if MIN_CHANNEL_ID <= peer_id < MAX_CHANNEL_ID: + return "channel" + elif 0 < peer_id <= MAX_USER_ID: + return "user" + + raise ValueError(f"Peer id invalid: {peer_id}") + + +async def get_user_and_name(message): + if message.reply_to_message.from_user: + return ( + message.reply_to_message.from_user.id, + message.reply_to_message.from_user.first_name, + ) + elif message.reply_to_message.sender_chat: + return ( + message.reply_to_message.sender_chat.id, + message.reply_to_message.sender_chat.title, + ) + + +@Client.on_message(filters.command(["ban"], prefix) & filters.me) +async def ban_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + user_for_ban, name = await get_user_and_name(message) + try: + await client.ban_chat_member(message.chat.id, user_for_ban) + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer(user_for_ban) + if "report_spam" in cause.lower().split(): + await client.send( + functions.channels.ReportSpam( + channel=channel, + participant=user_id, + id=[message.reply_to_message.message_id], + ) + ) + if "delete_history" in cause.lower().split(): + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + text_c = "".join( + f" {_}" + for _ in cause.split() + if _.lower() not in ["delete_history", "report_spam"] + ) + + await message.edit( + f"{name} banned!" + + f"\n{'Cause: ' + text_c.split(maxsplit=1)[1] + '' if len(text_c.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + if await check_username_or_id(cause.split(" ")[1]) == "channel": + user_to_ban = await client.get_chat(cause.split(" ")[1]) + elif await check_username_or_id(cause.split(" ")[1]) == "user": + user_to_ban = await client.get_users(cause.split(" ")[1]) + else: + await message.edit("Invalid user type") + return + + name = ( + user_to_ban.first_name + if getattr(user_to_ban, "first_name", None) + else user_to_ban.title + ) + + try: + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer(user_to_ban.id) + if ( + "report_spam" in cause.lower().split() + and message.reply_to_message + ): + await client.send( + functions.channels.ReportSpam( + channel=channel, + participant=user_id, + id=[message.reply_to_message.message_id], + ) + ) + if "delete_history" in cause.lower().split(): + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + + text_c = "".join( + f" {_}" + for _ in cause.split() + if _.lower() not in ["delete_history", "report_spam"] + ) + + await client.ban_chat_member(message.chat.id, user_to_ban.id) + await message.edit( + f"{name} banned!" + + f"\n{'Cause: ' + text_c.split(' ', maxsplit=2)[2] + '' if len(text_c.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["unban"], prefix) & filters.me) +async def unban_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + user_for_unban, name = await get_user_and_name(message) + try: + await client.unban_chat_member(message.chat.id, user_for_unban) + await message.edit( + f"{name} unbanned!" + + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + if await check_username_or_id(cause.split(" ")[1]) == "channel": + user_to_unban = await client.get_chat(cause.split(" ")[1]) + elif await check_username_or_id(cause.split(" ")[1]) == "user": + user_to_unban = await client.get_users(cause.split(" ")[1]) + else: + await message.edit("Invalid user type") + return + + name = ( + user_to_unban.first_name + if getattr(user_to_unban, "first_name", None) + else user_to_unban.title + ) + + try: + await client.unban_chat_member(message.chat.id, user_to_unban.id) + await message.edit( + f"{name} unbanned!" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["kick"], prefix) & filters.me) +async def kick_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + if message.reply_to_message.from_user: + try: + await client.ban_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + int(time() + 60), + ) + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer( + message.reply_to_message.from_user.id + ) + if "report_spam" in cause.lower().split() and message.reply_to_message: + await client.send( + functions.channels.ReportSpam( + channel=channel, + participant=user_id, + id=[message.reply_to_message.message_id], + ) + ) + if "delete_history" in cause.lower().split(): + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + text_c = "".join( + f" {_}" + for _ in cause.split() + if _.lower() not in ["delete_history", "report_spam"] + ) + + await message.edit( + f"{message.reply_to_message.from_user.first_name} kicked!" + + f"\n{'Cause: ' + text_c.split(maxsplit=1)[1] + '' if len(text_c.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + else: + await message.edit("Reply on user msg") + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + user_to_ban = await client.get_users(cause.split(" ")[1]) + try: + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer(user_to_ban.id) + if ( + "report_spam" in cause.lower().split() + and message.reply_to_message + ): + await client.send( + functions.channels.ReportSpam( + channel=channel, + participant=user_id, + id=[message.reply_to_message.message_id], + ) + ) + if "delete_history" in cause.lower().split(): + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + + text_c = "".join( + f" {_}" + for _ in cause.split() + if _.lower() not in ["delete_history", "report_spam"] + ) + + await client.ban_chat_member( + message.chat.id, user_to_ban.id, int(time() + 60) + ) + await message.edit( + f"{user_to_ban.first_name} kicked!" + + f"\n{'Cause: ' + text_c.split(' ', maxsplit=2)[2] + '' if len(text_c.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["kickdel"], prefix) & filters.me) +async def kickdel_cmd(_, message: Message): + await message.edit("Kicking deleted accounts...") + # noinspection PyTypeChecker + values = [ + await message.chat.ban_member(user.user.id, int(time()) + 31) + for member in await message.chat.get_members() + if member.user.is_deleted + ] + await message.edit(f"Successfully kicked {len(values)} deleted account(s)") + + +@Client.on_message(filters.command(["tmute"], prefix) & filters.me) +async def tmute_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + user_for_tmute, name = await get_user_and_name(message) + + if ( + message.reply_to_message.from_user + and message.reply_to_message.from_user.is_self + ): + return await message.edit("Not on yourself") + + tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) + if user_for_tmute not in tmuted_users: + tmuted_users.append(user_for_tmute) + db.set("core.ats", f"c{message.chat.id}", tmuted_users) + await message.edit( + f"{name} in tmute" + + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + else: + await message.edit(f"{name} already in tmute") + + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + if await check_username_or_id(cause.split(" ")[1]) == "channel": + user_to_tmute = await client.get_chat(cause.split(" ")[1]) + elif await check_username_or_id(cause.split(" ")[1]) == "user": + user_to_tmute = await client.get_users(cause.split(" ")[1]) + if user_to_tmute.is_self: + return await message.edit("Not on yourself") + else: + await message.edit("Invalid user type") + return + + name = ( + user_to_tmute.first_name + if getattr(user_to_tmute, "first_name", None) + else user_to_tmute.title + ) + + tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) + if user_to_tmute.id not in tmuted_users: + tmuted_users.append(user_to_tmute.id) + db.set("core.ats", f"c{message.chat.id}", tmuted_users) + await message.edit( + f"{name} in tmute" + + f"\n{'Cause: ' + cause.split(maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + else: + await message.edit(f"{name} already in tmute") + + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + update_cache() + + +@Client.on_message(filters.command(["tunmute"], prefix) & filters.me) +async def tunmute_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + user_for_tunmute, name = await get_user_and_name(message) + + tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) + if user_for_tunmute not in tmuted_users: + await message.edit(f"{name} not in tmute") + else: + tmuted_users.remove(user_for_tunmute) + db.set("core.ats", f"c{message.chat.id}", tmuted_users) + await message.edit( + f"{name} tunmuted" + + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + if await check_username_or_id(cause.split(" ")[1]) == "channel": + user_to_tunmute = await client.get_chat(cause.split(" ")[1]) + elif await check_username_or_id(cause.split(" ")[1]) == "user": + user_to_tunmute = await client.get_users(cause.split(" ")[1]) + if user_to_tunmute.is_self: + return await message.edit("Not on yourself") + else: + await message.edit("Invalid user type") + return + + name = ( + user_to_tunmute.first_name + if getattr(user_to_tunmute, "first_name", None) + else user_to_tunmute.title + ) + + tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) + if user_to_tunmute.id not in tmuted_users: + await message.edit(f"{name} not in tmute") + else: + tmuted_users.remove(user_to_tunmute.id) + db.set("core.ats", f"c{message.chat.id}", tmuted_users) + await message.edit( + f"{name} tunmuted" + + f"\n{'Cause: ' + cause.split(maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + update_cache() + + +@Client.on_message(filters.command(["tmute_users"], prefix) & filters.me) +async def tunmute_users_command(client: Client, message: Message): + if message.chat.type not in ["private", "channel"]: + text = f"All users {message.chat.title} who are now in tmute\n\n" + count = 0 + tmuted_users = db.get("core.ats", f"c{message.chat.id}", []) + for user in tmuted_users: + try: + _name_ = await client.get_chat(user) + count += 1 + if await check_username_or_id(_name_.id) == "channel": + channel = await client.send( + functions.channels.GetChannels( + id=[ + types.InputChannel( + channel_id=get_channel_id(_name_.id), + access_hash=0, + ) + ] + ) + ) + name = channel.chats[0].title + elif await check_username_or_id(_name_.id) == "user": + user = await client.get_users(_name_.id) + name = user.first_name + else: + # invalid user type + continue + text += f"{count}. {name}\n" + except PeerIdInvalid: + pass + if count == 0: + await message.edit("No users in tmute") + else: + text += f"\nTotal users in tmute {count}" + await message.edit(text) + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["unmute"], prefix) & filters.me) +async def unmute_command(client, message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + u_p = message.chat.permissions + if message.reply_to_message.from_user: + try: + await client.restrict_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + u_p, + int(time() + 30), + ) + await message.edit( + f"{message.reply_to_message.from_user.first_name} unmuted" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + else: + await message.edit("Reply on user msg") + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + u_p = message.chat.permissions + if len(cause.split()) > 1: + try: + user_to_unmute = await client.get_users(cause.split(" ")[1]) + try: + await client.restrict_chat_member( + message.chat.id, user_to_unmute.id, u_p, int( + time() + 30) + ) + await message.edit( + f"{user_to_unmute.first_name} unmuted!" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["mute"], prefix) & filters.me) +async def mute_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + mute_seconds: int = 0 + for character in "mhdw": + match = re.search(rf"(\d+|(\d+\.\d+)){character}", message.text) + if match: + if character == "m": + mute_seconds += int( + float(match.string[match.start() + : match.end() - 1]) * 60 // 1 + ) + if character == "h": + mute_seconds += int( + float(match.string[match.start() + : match.end() - 1]) * 3600 // 1 + ) + if character == "d": + mute_seconds += int( + float(match.string[match.start(): match.end() - 1]) + * 86400 + // 1 + ) + if character == "w": + mute_seconds += int( + float(match.string[match.start(): match.end() - 1]) + * 604800 + // 1 + ) + try: + if mute_seconds > 30: + await client.restrict_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + ChatPermissions(), + int(time()) + mute_seconds, + ) + from_user = message.reply_to_message.from_user + mute_time: Dict[str, int] = { + "days": mute_seconds // 86400, + "hours": mute_seconds % 86400 // 3600, + "minutes": mute_seconds % 86400 % 3600 // 60, + } + message_text = ( + f"{from_user.first_name} was muted for" + f" {((str(mute_time['days']) + ' day') if mute_time['days'] > 0 else '') + ('s' if mute_time['days'] > 1 else '')}" + f" {((str(mute_time['hours']) + ' hour') if mute_time['hours'] > 0 else '') + ('s' if mute_time['hours'] > 1 else '')}" + f" {((str(mute_time['minutes']) + ' minute') if mute_time['minutes'] > 0 else '') + ('s' if mute_time['minutes'] > 1 else '')}" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + while " " in message_text: + message_text = message_text.replace(" ", " ") + else: + await client.restrict_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + ChatPermissions(), + ) + message_text = ( + f"{message.reply_to_message.from_user.first_name} was muted indefinitely" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + await message.edit(message_text) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + user_to_unmute = await client.get_users(cause.split(" ")[1]) + mute_seconds: int = 0 + for character in "mhdw": + match = re.search( + rf"(\d+|(\d+\.\d+)){character}", message.text) + if match: + if character == "m": + mute_seconds += int( + float( + match.string[match.start(): match.end() - 1]) + * 60 + // 1 + ) + if character == "h": + mute_seconds += int( + float( + match.string[match.start(): match.end() - 1]) + * 3600 + // 1 + ) + if character == "d": + mute_seconds += int( + float( + match.string[match.start(): match.end() - 1]) + * 86400 + // 1 + ) + if character == "w": + mute_seconds += int( + float( + match.string[match.start(): match.end() - 1]) + * 604800 + // 1 + ) + try: + if mute_seconds > 30: + await client.restrict_chat_member( + message.chat.id, + user_to_unmute.id, + ChatPermissions(), + int(time()) + mute_seconds, + ) + mute_time: Dict[str, int] = { + "days": mute_seconds // 86400, + "hours": mute_seconds % 86400 // 3600, + "minutes": mute_seconds % 86400 % 3600 // 60, + } + message_text = ( + f"{user_to_unmute.first_name} was muted for" + f" {((str(mute_time['days']) + ' day') if mute_time['days'] > 0 else '') + ('s' if mute_time['days'] > 1 else '')}" + f" {((str(mute_time['hours']) + ' hour') if mute_time['hours'] > 0 else '') + ('s' if mute_time['hours'] > 1 else '')}" + f" {((str(mute_time['minutes']) + ' minute') if mute_time['minutes'] > 0 else '') + ('s' if mute_time['minutes'] > 1 else '')}" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=3)[3] + '' if len(cause.split()) > 3 else ''}" + ) + while " " in message_text: + message_text = message_text.replace(" ", " ") + else: + await client.restrict_chat_member( + message.chat.id, user_to_unmute.id, ChatPermissions() + ) + message_text = ( + f"{user_to_unmute.first_name} was muted indefinitely" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + await message.edit(message_text) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["demote"], prefix) & filters.me) +async def demote_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + if message.reply_to_message.from_user: + try: + await client.promote_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + is_anonymous=False, + can_manage_chat=False, + can_change_info=False, + can_post_messages=False, + can_edit_messages=False, + can_delete_messages=False, + can_restrict_members=False, + can_invite_users=False, + can_pin_messages=False, + can_promote_members=False, + can_manage_voice_chats=False, + ) + await message.edit( + f"{message.reply_to_message.from_user.first_name} demoted!" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + promote_user = await client.get_users(cause.split(" ")[1]) + try: + await client.promote_chat_member( + message.chat.id, + promote_user.id, + is_anonymous=False, + can_manage_chat=False, + can_change_info=False, + can_post_messages=False, + can_edit_messages=False, + can_delete_messages=False, + can_restrict_members=False, + can_invite_users=False, + can_pin_messages=False, + can_promote_members=False, + can_manage_voice_chats=False, + ) + await message.edit( + f"{promote_user.first_name} demoted!" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["promote"], prefix) & filters.me) +async def promote_command(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + if message.reply_to_message.from_user: + try: + await client.promote_chat_member( + message.chat.id, + message.reply_to_message.from_user.id, + can_delete_messages=True, + can_restrict_members=True, + can_invite_users=True, + can_pin_messages=True, + ) + if len(cause.split()) > 1: + await client.set_administrator_title( + message.chat.id, + message.reply_to_message.from_user.id, + cause.split(maxsplit=1)[1], + ) + await message.edit( + f"{message.reply_to_message.from_user.first_name} promoted!" + + f"\n{'Prefix: ' + cause.split(' ', maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + promote_user = await client.get_users(cause.split(" ")[1]) + try: + await client.promote_chat_member( + message.chat.id, + promote_user.id, + can_delete_messages=True, + can_restrict_members=True, + can_invite_users=True, + can_pin_messages=True, + ) + if len(cause.split()) > 1: + await client.set_administrator_title( + message.chat.id, + promote_user.id, + f"\n{cause.split(' ', maxsplit=2)[2] if len(cause.split()) > 2 else None}", + ) + await message.edit( + f"{promote_user.first_name} promoted!" + + f"\n{'Prefix: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["antich"], prefix)) +async def anti_channels(client: Client, message: Message): + if message.chat.type != "supergroup": + await message.edit("Not supported in non-supergroup chats") + return + + if len(message.command) == 1: + if db.get("core.ats", f"antich{message.chat.id}", False): + await message.edit( + "Blocking channels in this chat is enabled.\n" + f"Disable with: {prefix}antich disable" + ) + else: + await message.edit( + "Blocking channels in this chat is disabled.\n" + f"Enable with: {prefix}antich enable" + ) + elif message.command[1] in ["enable", "on", "1", "yes", "true"]: + db.set("core.ats", f"antich{message.chat.id}", True) + group = await client.get_chat(message.chat.id) + if group.linked_chat: + db.set( + "core.ats", f"linked{message.chat.id}", group.linked_chat.id) + else: + db.set("core.ats", f"linked{message.chat.id}", 0) + await message.edit("Blocking channels in this chat enabled.") + elif message.command[1] in ["disable", "off", "0", "no", "false"]: + db.set("core.ats", f"antich{message.chat.id}", False) + await message.edit("Blocking channels in this chat disabled.") + else: + await message.edit(f"Usage: {prefix}antich [enable|disable]") + + update_cache() + + +@Client.on_message(filters.command(["delete_history", "dh"], prefix)) +async def delete_history(client: Client, message: Message): + cause = text(message) + if message.reply_to_message and message.chat.type not in ["private", "channel"]: + if message.reply_to_message.from_user: + try: + user_for_delete, name = await get_user_and_name(message) + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer(user_for_delete) + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + + await message.edit( + f"History from {name} was deleted!" + + f"\n{'Cause: ' + cause.split(maxsplit=1)[1] + '' if len(cause.split()) > 1 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + else: + await message.edit("Reply on user msg") + elif not message.reply_to_message and message.chat.type not in [ + "private", + "channel", + ]: + if len(cause.split()) > 1: + try: + if await check_username_or_id(cause.split(" ")[1]) == "channel": + user_to_delete = await client.get_chat(cause.split(" ")[1]) + elif await check_username_or_id(cause.split(" ")[1]) == "user": + user_to_delete = await client.get_users(cause.split(" ")[1]) + else: + await message.edit("Invalid user type") + return + + name = ( + user_to_delete.first_name + if getattr(user_to_delete, "first_name", None) + else user_to_delete.title + ) + + try: + channel = await client.resolve_peer(message.chat.id) + user_id = await client.resolve_peer(user_to_delete.id) + await client.send( + functions.channels.DeleteParticipantHistory( + channel=channel, participant=user_id + ) + ) + await message.edit( + f"History from {name} was deleted!" + + f"\n{'Cause: ' + cause.split(' ', maxsplit=2)[2] + '' if len(cause.split()) > 2 else ''}" + ) + except UserAdminInvalid: + await message.edit("No rights") + except ChatAdminRequired: + await message.edit("No rights") + except Exception as e: + await message.edit(format_exc(e)) + except PeerIdInvalid: + await message.edit("User is not found") + except UsernameInvalid: + await message.edit("User is not found") + except IndexError: + await message.edit("User is not found") + else: + await message.edit("user_id or username") + else: + await message.edit("Unsupported") + + +@Client.on_message(filters.command(["report_spam", "rs"], prefix)) +@with_reply +async def report_spam(client: Client, message: Message): + try: + channel = await client.resolve_peer(message.chat.id) + + user_id, name = await get_user_and_name(message) + peer = await client.resolve_peer(user_id) + await client.send( + functions.channels.ReportSpam( + channel=channel, + participant=peer, + id=[message.reply_to_message.message_id], + ) + ) + except Exception as e: + await message.edit(format_exc(e)) + else: + await message.edit(f"Message from {name} was reported") + + +@Client.on_message(filters.command("pin", prefix) & filters.me) +@with_reply +async def pin(_, message: Message): + try: + await message.reply_to_message.pin() + await message.edit("Pinned!") + except Exception as e: + await message.edit(format_exc(e)) + + +@Client.on_message(filters.command("unpin", prefix) & filters.me) +@with_reply +async def unpin(_, message: Message): + try: + await message.reply_to_message.unpin() + await message.edit("Unpinned!") + except Exception as e: + await message.edit(format_exc(e)) + + +@Client.on_message(filters.command("ro", prefix) & filters.me) +async def ro(client: Client, message: Message): + if message.chat.type != "supergroup": + await message.edit("Invalid chat type") + return + + try: + perms = message.chat.permissions + perms_list = [ + perms.can_send_messages, + perms.can_send_media_messages, + perms.can_send_other_messages, + perms.can_send_polls, + perms.can_add_web_page_previews, + perms.can_change_info, + perms.can_invite_users, + perms.can_pin_messages, + ] + db.set("core.ats", f"ro{message.chat.id}", perms_list) + + try: + await client.set_chat_permissions(message.chat.id, ChatPermissions()) + except (UserAdminInvalid, ChatAdminRequired): + await message.edit("No rights") + else: + await message.edit( + "Read-only mode activated!\n" + f"Turn off with:{prefix}unro" + ) + except Exception as e: + await message.edit(format_exc(e)) + + +@Client.on_message(filters.command("unro", prefix) & filters.me) +async def unro(client: Client, message: Message): + if message.chat.type != "supergroup": + await message.edit("Invalid chat type") + return + + try: + perms_list = db.get( + "core.ats", + f"ro{message.chat.id}", + [True, True, True, False, False, False, False, False], + ) + perms = ChatPermissions( + can_send_messages=perms_list[0], + can_send_media_messages=perms_list[1], + can_send_other_messages=perms_list[2], + can_send_polls=perms_list[3], + can_add_web_page_previews=perms_list[4], + can_change_info=perms_list[5], + can_invite_users=perms_list[6], + can_pin_messages=perms_list[7], + ) + + try: + await client.set_chat_permissions(message.chat.id, perms) + except (UserAdminInvalid, ChatAdminRequired): + await message.edit("No rights") + else: + await message.edit("Read-only mode disabled!") + except Exception as e: + await message.edit(format_exc(e)) + + +@Client.on_message(filters.command("antiraid", prefix) & filters.me) +async def antiraid(client: Client, message: Message): + if message.chat.type != "supergroup": + await message.edit("Not supported in non-supergroup chats") + return + + if len(message.command) > 1 and message.command[1] == "on": + db.set("core.ats", f"antiraid{message.chat.id}", True) + group = await client.get_chat(message.chat.id) + if group.linked_chat: + db.set( + "core.ats", f"linked{message.chat.id}", group.linked_chat.id) + else: + db.set("core.ats", f"linked{message.chat.id}", 0) + await message.edit( + "Anti-raid mode enabled!\n" + f"Disable with: {prefix}antiraid off" + ) + elif len(message.command) > 1 and message.command[1] == "off": + db.set("core.ats", f"antiraid{message.chat.id}", False) + await message.edit("Anti-raid mode disabled") + else: + # toggle + if db.get("core.ats", f"antiraid{message.chat.id}", False): + db.set("core.ats", f"antiraid{message.chat.id}", False) + await message.edit("Anti-raid mode disabled") + else: + db.set("core.ats", f"antiraid{message.chat.id}", True) + group = await client.get_chat(message.chat.id) + if group.linked_chat: + db.set( + "core.ats", f"linked{message.chat.id}", group.linked_chat.id) + else: + db.set("core.ats", f"linked{message.chat.id}", 0) + await message.edit( + "Anti-raid mode enabled!\n" + f"Disable with: {prefix}antiraid off" + ) + + update_cache() + + +@Client.on_message(filters.command(["welcome", "wc"], prefix) & filters.me) +async def welcome(_, message: Message): + if message.chat.type != "supergroup": + return await message.edit("Unsupported chat type") + + if len(message.command) > 1: + text = message.text.split(maxsplit=1)[1] + db.set("core.ats", f"welcome_enabled{message.chat.id}", True) + db.set("core.ats", f"welcome_text{message.chat.id}", text) + + await message.edit( + f"Welcome enabled in this chat\nText: {text}" + ) + else: + db.set("core.ats", f"welcome_enabled{message.chat.id}", False) + await message.edit("Welcome disabled in this chat") + + update_cache() + + +modules_help["admintool"] = { + "ban [reply]/[username/id]* [reason] [report_spam] [delete_history]": "ban user in chat", + "unban [reply]/[username/id]* [reason]": "unban user in chat", + "kick [reply]/[userid]* [reason] [report_spam] [delete_history]": "kick user out of chat", + "mute [reply]/[userid]* [reason] [1m]/[1h]/[1d]/[1w]": "mute user in chat", + "unmute [reply]/[userid]* [reason]": "unmute user in chat", + "promote [reply]/[userid]* [prefix]": "promote user in chat", + "demote [reply]/[userid]* [reason]": "demote user in chat", + "tmute [reply]/[username/id]* [reason]": "delete all new messages from user in chat", + "tunmute [reply]/[username/id]* [reason]": "stop deleting all messages from user in chat", + "tmute_users": "list of tmuted (.tmute) users", + "antich [enable/disable]": "turn on/off blocking channels in this chat", + "delete_history [reply]/[username/id]* [reason]": "delete history from member in chat", + "report_spam [reply]*": "report spam message in chat", + "pin [reply]*": "Pin replied message", + "unpin [reply]*": "Unpin replied message", + "ro": "enable read-only mode", + "unro": "disable read-only mode", + "antiraid [on|off]": "when enabled, anyone who writes message will be blocked. Useful in raids. " + "Running without arguments equals to toggling state", + "welcome [text]*": "enable auto-welcome to new users in groups. " + "Running without text equals to disable", + "kickdel": "Kick all deleted accounts", +} diff --git a/modules/admlist.py b/modules/admlist.py index 9199dd5..8e9bf65 100644 --- a/modules/admlist.py +++ b/modules/admlist.py @@ -1,129 +1,129 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - import json - from html import escape as t - from time import perf_counter - - from pyrogram import Client, filters - from pyrogram.errors.exceptions.flood_420 import FloodWait - from pyrogram.raw.functions.messages.get_all_chats import GetAllChats - from pyrogram.types import Message - - from utils.misc import modules_help, prefix - from utils.scripts import format_exc - - - @Client.on_message(filters.command("admcount", prefix) & filters.me) - async def admcount(client: Client, message: Message): -     await message.edit("Retrieving information... (it'll take some time)") - -     start = perf_counter() -     try: -         response = await client.send(GetAllChats(except_ids=[])) -         chats = response["chats"] - -         adminned_chats = 0 -         owned_chats = 0 -         owned_usernamed_chats = 0 - -         for chat in chats: -             if getattr(chat, "migrated_to", None): -                 continue -             if chat.creator and getattr(chat, "username", None): -                 owned_usernamed_chats += 1 -             elif chat.creator: -                 owned_chats += 1 -             elif getattr(chat, "admin_rights", None): -                 adminned_chats += 1 -     except Exception as e: -         await message.edit(format_exc(e)) -         return - -     stop = perf_counter() - -     await message.edit( -         f"Total: {adminned_chats + owned_chats + owned_usernamed_chats}" -         f"\nAdminned chats: {adminned_chats}\n" -         f"Owned chats: {owned_chats}\n" -         f"Owned chats with username: {owned_usernamed_chats}\n\n" -         f"Done at {round(stop - start, 3)} seconds.\n\n" -         f"Get full list: {prefix}admlist" -     ) - - - @Client.on_message(filters.command("admlist", prefix) & filters.me) - async def admlist(client: Client, message: Message): -     await message.edit("Retrieving information... (it'll take some time)") - -     start = perf_counter() -     try: -         response = await client.send(GetAllChats(except_ids=[])) -         chats = response["chats"] - -         adminned_chats = [] -         owned_chats = [] -         owned_usernamed_chats = [] - -         for chat in chats: -             if getattr(chat, "migrated_to", None) is not None: -                 continue -             if chat.creator and getattr(chat, "username", None): -                 owned_usernamed_chats.append(chat) -             elif chat.creator: -                 owned_chats.append(chat) -             elif getattr(chat, "admin_rights", None): -                 adminned_chats.append(chat) - -         text = "Adminned chats:\n" -         for index, chat in enumerate(adminned_chats): -             text += ( -                 f"{index + 1}. {chat.title}\n" -             ) - -         text += "\nOwned chats:\n" -         for index, chat in enumerate(owned_chats): -             text += ( -                 f"{index + 1}. {chat.title}\n" -             ) - -         text += "\nOwned chats with username:\n" -         for index, chat in enumerate(owned_usernamed_chats): -             text += ( -                 f"{index + 1}. {chat.title}\n" -             ) - -         stop = perf_counter() -         total_count = ( -             len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats) -         ) -         await message.edit( -             text + "\n" -             f"Total: {total_count}" -             f"\nAdminned chats: {len(adminned_chats)}\n" -             f"Owned chats: {len(owned_chats)}\n" -             f"Owned chats with username: {len(owned_usernamed_chats)}\n\n" -             f"Done at {round(stop - start, 3)} seconds." -         ) -     except Exception as e: -         await message.edit(format_exc(e)) -         return - - - modules_help["admlist"] = { -     "admcount": "Get count of adminned and owned chats", -     "admlist": "Get list of adminned and owned chats", - } \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import json +from html import escape as t +from time import perf_counter + +from pyrogram import Client, filters +from pyrogram.errors.exceptions.flood_420 import FloodWait +from pyrogram.raw.functions.messages.get_all_chats import GetAllChats +from pyrogram.types import Message + +from utils.misc import modules_help, prefix +from utils.scripts import format_exc + + +@Client.on_message(filters.command("admcount", prefix) & filters.me) +async def admcount(client: Client, message: Message): + await message.edit("Retrieving information... (it'll take some time)") + + start = perf_counter() + try: + response = await client.send(GetAllChats(except_ids=[])) + chats = response["chats"] + + adminned_chats = 0 + owned_chats = 0 + owned_usernamed_chats = 0 + + for chat in chats: + if getattr(chat, "migrated_to", None): + continue + if chat.creator and getattr(chat, "username", None): + owned_usernamed_chats += 1 + elif chat.creator: + owned_chats += 1 + elif getattr(chat, "admin_rights", None): + adminned_chats += 1 + except Exception as e: + await message.edit(format_exc(e)) + return + + stop = perf_counter() + + await message.edit( + f"Total: {adminned_chats + owned_chats + owned_usernamed_chats}" + f"\nAdminned chats: {adminned_chats}\n" + f"Owned chats: {owned_chats}\n" + f"Owned chats with username: {owned_usernamed_chats}\n\n" + f"Done at {round(stop - start, 3)} seconds.\n\n" + f"Get full list: {prefix}admlist" + ) + + +@Client.on_message(filters.command("admlist", prefix) & filters.me) +async def admlist(client: Client, message: Message): + await message.edit("Retrieving information... (it'll take some time)") + + start = perf_counter() + try: + response = await client.send(GetAllChats(except_ids=[])) + chats = response["chats"] + + adminned_chats = [] + owned_chats = [] + owned_usernamed_chats = [] + + for chat in chats: + if getattr(chat, "migrated_to", None) is not None: + continue + if chat.creator and getattr(chat, "username", None): + owned_usernamed_chats.append(chat) + elif chat.creator: + owned_chats.append(chat) + elif getattr(chat, "admin_rights", None): + adminned_chats.append(chat) + + text = "Adminned chats:\n" + for index, chat in enumerate(adminned_chats): + text += ( + f"{index + 1}. {chat.title}\n" + ) + + text += "\nOwned chats:\n" + for index, chat in enumerate(owned_chats): + text += ( + f"{index + 1}. {chat.title}\n" + ) + + text += "\nOwned chats with username:\n" + for index, chat in enumerate(owned_usernamed_chats): + text += ( + f"{index + 1}. {chat.title}\n" + ) + + stop = perf_counter() + total_count = ( + len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats) + ) + await message.edit( + text + "\n" + f"Total: {total_count}" + f"\nAdminned chats: {len(adminned_chats)}\n" + f"Owned chats: {len(owned_chats)}\n" + f"Owned chats with username: {len(owned_usernamed_chats)}\n\n" + f"Done at {round(stop - start, 3)} seconds." + ) + except Exception as e: + await message.edit(format_exc(e)) + return + + +modules_help["admlist"] = { + "admcount": "Get count of adminned and owned chats", + "admlist": "Get list of adminned and owned chats", +} diff --git a/modules/afk.py b/modules/afk.py index 567dfcf..4c8dbec 100644 --- a/modules/afk.py +++ b/modules/afk.py @@ -1,85 +1,86 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - import datetime - - from pyrogram import Client, filters, types - - from utils.misc import modules_help, prefix - from utils.db import db - - - # avoid using global variables - afk_info = db.get( -     "core.afk", -     "afk_info", -     { -         "start": 0, -         "is_afk": False, -         "reason": "", -     }, - ) - - is_afk = filters.create(lambda _, __, ___: afk_info["is_afk"]) - - - @Client.on_message( -     is_afk -     & (filters.private | filters.mentioned) -     & ~filters.channel -     & ~filters.me -     & ~filters.bot - ) - async def afk_handler(_, message: types.Message): -     start = datetime.datetime.fromtimestamp(afk_info["start"]) -     end = datetime.datetime.now().replace(microsecond=0) -     afk_time = end - start -     await message.reply( -         f"I'm AFK {afk_time}\n" f"Reason: {afk_info['reason']}" -     ) - - - @Client.on_message(filters.command("afk", prefix) & filters.me) - async def afk(_, message): -     if len(message.text.split()) >= 2: -         reason = message.text.split(" ", maxsplit=1)[1] -     else: -         reason = "None" - -     afk_info["start"] = int(datetime.datetime.now().timestamp()) -     afk_info["is_afk"] = True -     afk_info["reason"] = reason - -     await message.edit(f"I'm going AFK.\n" f"Reason: {reason}") - -     db.set("core.afk", "afk_info", afk_info) - - - @Client.on_message(filters.command("unafk", prefix) & filters.me) - async def unafk(_, message): -     if afk_info["is_afk"]: -         start = datetime.datetime.fromtimestamp(afk_info["start"]) -         end = datetime.datetime.now().replace(microsecond=0) -         afk_time = end - start -         await message.edit(f"I'm not AFK anymore.\n" f"I was afk {afk_time}") -         afk_info["is_afk"] = False -     else: -         await message.edit("You weren't afk") - -     db.set("core.afk", "afk_info", afk_info) - - - modules_help["afk"] = {"afk [reason]": "Go to afk", "unafk": "Get out of AFK"} \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import datetime + +from pyrogram import Client, filters, types + +from utils.misc import modules_help, prefix +from utils.db import db + + +# avoid using global variables +afk_info = db.get( + "core.afk", + "afk_info", + { + "start": 0, + "is_afk": False, + "reason": "", + }, +) + +is_afk = filters.create(lambda _, __, ___: afk_info["is_afk"]) + + +@Client.on_message( + is_afk + & (filters.private | filters.mentioned) + & ~filters.channel + & ~filters.me + & ~filters.bot +) +async def afk_handler(_, message: types.Message): + start = datetime.datetime.fromtimestamp(afk_info["start"]) + end = datetime.datetime.now().replace(microsecond=0) + afk_time = end - start + await message.reply( + f"I'm AFK {afk_time}\n" f"Reason: {afk_info['reason']}" + ) + + +@Client.on_message(filters.command("afk", prefix) & filters.me) +async def afk(_, message): + if len(message.text.split()) >= 2: + reason = message.text.split(" ", maxsplit=1)[1] + else: + reason = "None" + + afk_info["start"] = int(datetime.datetime.now().timestamp()) + afk_info["is_afk"] = True + afk_info["reason"] = reason + + await message.edit(f"I'm going AFK.\n" f"Reason: {reason}") + + db.set("core.afk", "afk_info", afk_info) + + +@Client.on_message(filters.command("unafk", prefix) & filters.me) +async def unafk(_, message): + if afk_info["is_afk"]: + start = datetime.datetime.fromtimestamp(afk_info["start"]) + end = datetime.datetime.now().replace(microsecond=0) + afk_time = end - start + await message.edit(f"I'm not AFK anymore.\n" f"I was afk {afk_time}") + afk_info["is_afk"] = False + else: + await message.edit("You weren't afk") + + db.set("core.afk", "afk_info", afk_info) + + +modules_help["afk"] = { + "afk [reason]": "Go to afk(note that afk module is not fully completed yet so to unafk it's unable tp detect user messages and disable automatically so you'll have to manually use .unafk command for a while ASAP )", "unafk": "Get out of AFK"} diff --git a/modules/antipm.py b/modules/antipm.py index e34e65e..bee6ed9 100644 --- a/modules/antipm.py +++ b/modules/antipm.py @@ -1,125 +1,126 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - from pyrogram import Client, filters - from pyrogram.raw import functions - from pyrogram.types import Message - - from utils.db import db - from utils.misc import modules_help, prefix - - anti_pm_enabled = filters.create( -     lambda _, __, ___: db.get("core.antipm", "status", False) - ) - - in_contact_list = filters.create(lambda _, __, message: message.from_user.is_contact) - - is_support = filters.create(lambda _, __, message: message.chat.is_support) - - - @Client.on_message( -     filters.private -     & ~filters.me -     & ~filters.bot -     & ~in_contact_list -     & ~is_support -     & anti_pm_enabled - ) - async def anti_pm_handler(client: Client, message: Message): -     user_info = await client.resolve_peer(message.chat.id) -     if db.get("core.antipm", "spamrep", False): -         await client.send(functions.messages.ReportSpam(peer=user_info)) -     if db.get("core.antipm", "block", False): -         await client.send(functions.contacts.Block(id=user_info)) -     await client.send( -         functions.messages.DeleteHistory(peer=user_info, max_id=0, revoke=True) -     ) - - - @Client.on_message(filters.command(["antipm", "anti_pm"], prefix) & filters.me) - async def anti_pm(_, message: Message): -     if len(message.command) == 1: -         if db.get("core.antipm", "status", False): -             await message.edit( -                 "Anti-PM status: enabled\n" -                 f"Disable with: {prefix}antipm disable" -             ) -         else: -             await message.edit( -                 "Anti-PM status: disabled\n" -                 f"Enable with: {prefix}antipm enable" -             ) -     elif message.command[1] in ["enable", "on", "1", "yes", "true"]: -         db.set("core.antipm", "status", True) -         await message.edit("Anti-PM enabled!") -     elif message.command[1] in ["disable", "off", "0", "no", "false"]: -         db.set("core.antipm", "status", False) -         await message.edit("Anti-PM disabled!") -     else: -         await message.edit(f"Usage: {prefix}antipm [enable|disable]") - - - @Client.on_message(filters.command(["antipm_report"], prefix) & filters.me) - async def antipm_report(_, message: Message): -     if len(message.command) == 1: -         if db.get("core.antipm", "spamrep", False): -             await message.edit( -                 "Spam-reporting enabled.\n" -                 f"Disable with: {prefix}antipm_report disable" -             ) -         else: -             await message.edit( -                 "Spam-reporting disabled.\n" -                 f"Enable with: {prefix}antipm_report enable" -             ) -     elif message.command[1] in ["enable", "on", "1", "yes", "true"]: -         db.set("core.antipm", "spamrep", True) -         await message.edit("Spam-reporting enabled!") -     elif message.command[1] in ["disable", "off", "0", "no", "false"]: -         db.set("core.antipm", "spamrep", False) -         await message.edit("Spam-reporting disabled!") -     else: -         await message.edit(f"Usage: {prefix}antipm_report [enable|disable]") - - - @Client.on_message(filters.command(["antipm_block"], prefix) & filters.me) - async def antipm_block(_, message: Message): -     if len(message.command) == 1: -         if db.get("core.antipm", "block", False): -             await message.edit( -                 "Blocking users enabled.\n" -                 f"Disable with: {prefix}antipm_block disable" -             ) -         else: -             await message.edit( -                 "Blocking users disabled.\n" -                 f"Enable with: {prefix}antipm_block enable" -             ) -     elif message.command[1] in ["enable", "on", "1", "yes", "true"]: -         db.set("core.antipm", "block", True) -         await message.edit("Blocking users enabled!") -     elif message.command[1] in ["disable", "off", "0", "no", "false"]: -         db.set("core.antipm", "block", False) -         await message.edit("Blocking users disabled!") -     else: -         await message.edit(f"Usage: {prefix}antipm_block [enable|disable]") - - - modules_help["antipm"] = { -     "antipm [enable|disable]*": "When enabled, deletes all messages from users who are not in the contact book", -     "antipm_report [enable|disable]*": "Enable spam reporting", -     "antipm_block [enable|disable]*": "Enable user blocking", - } \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from pyrogram import Client, filters +from pyrogram.raw import functions +from pyrogram.types import Message + +from utils.db import db +from utils.misc import modules_help, prefix + +anti_pm_enabled = filters.create( + lambda _, __, ___: db.get("core.antipm", "status", False) +) + +in_contact_list = filters.create( + lambda _, __, message: message.from_user.is_contact) + +is_support = filters.create(lambda _, __, message: message.chat.is_support) + + +@Client.on_message( + filters.private + & ~filters.me + & ~filters.bot + & ~in_contact_list + & ~is_support + & anti_pm_enabled +) +async def anti_pm_handler(client: Client, message: Message): + user_info = await client.resolve_peer(message.chat.id) + if db.get("core.antipm", "spamrep", False): + await client.send(functions.messages.ReportSpam(peer=user_info)) + if db.get("core.antipm", "block", False): + await client.send(functions.contacts.Block(id=user_info)) + await client.send( + functions.messages.DeleteHistory(peer=user_info, max_id=0, revoke=True) + ) + + +@Client.on_message(filters.command(["antipm", "anti_pm"], prefix) & filters.me) +async def anti_pm(_, message: Message): + if len(message.command) == 1: + if db.get("core.antipm", "status", False): + await message.edit( + "Anti-PM status: enabled\n" + f"Disable with: {prefix}antipm disable" + ) + else: + await message.edit( + "Anti-PM status: disabled\n" + f"Enable with: {prefix}antipm enable" + ) + elif message.command[1] in ["enable", "on", "1", "yes", "true"]: + db.set("core.antipm", "status", True) + await message.edit("Anti-PM enabled!") + elif message.command[1] in ["disable", "off", "0", "no", "false"]: + db.set("core.antipm", "status", False) + await message.edit("Anti-PM disabled!") + else: + await message.edit(f"Usage: {prefix}antipm [enable|disable]") + + +@Client.on_message(filters.command(["antipm_report"], prefix) & filters.me) +async def antipm_report(_, message: Message): + if len(message.command) == 1: + if db.get("core.antipm", "spamrep", False): + await message.edit( + "Spam-reporting enabled.\n" + f"Disable with: {prefix}antipm_report disable" + ) + else: + await message.edit( + "Spam-reporting disabled.\n" + f"Enable with: {prefix}antipm_report enable" + ) + elif message.command[1] in ["enable", "on", "1", "yes", "true"]: + db.set("core.antipm", "spamrep", True) + await message.edit("Spam-reporting enabled!") + elif message.command[1] in ["disable", "off", "0", "no", "false"]: + db.set("core.antipm", "spamrep", False) + await message.edit("Spam-reporting disabled!") + else: + await message.edit(f"Usage: {prefix}antipm_report [enable|disable]") + + +@Client.on_message(filters.command(["antipm_block"], prefix) & filters.me) +async def antipm_block(_, message: Message): + if len(message.command) == 1: + if db.get("core.antipm", "block", False): + await message.edit( + "Blocking users enabled.\n" + f"Disable with: {prefix}antipm_block disable" + ) + else: + await message.edit( + "Blocking users disabled.\n" + f"Enable with: {prefix}antipm_block enable" + ) + elif message.command[1] in ["enable", "on", "1", "yes", "true"]: + db.set("core.antipm", "block", True) + await message.edit("Blocking users enabled!") + elif message.command[1] in ["disable", "off", "0", "no", "false"]: + db.set("core.antipm", "block", False) + await message.edit("Blocking users disabled!") + else: + await message.edit(f"Usage: {prefix}antipm_block [enable|disable]") + + +modules_help["antipm"] = { + "antipm [enable|disable]*": "When enabled, deletes all messages from users who are not in the contact book", + "antipm_report [enable|disable]*": "Enable spam reporting", + "antipm_block [enable|disable]*": "Enable user blocking", +} diff --git a/modules/clear_notifs.py b/modules/clear_notifs.py index 8f5d254..195c5b1 100644 --- a/modules/clear_notifs.py +++ b/modules/clear_notifs.py @@ -1,72 +1,88 @@ -from pyrogram import Client, filters - from pyrogram.errors import FloodWait - from pyrogram.raw import functions, types - from pyrogram.types import Message - - from utils.misc import modules_help, prefix - - - @Client.on_message(filters.command(["clear_@"], prefix) & filters.me) - async def solo_mention_clear(client: Client, message: Message): -     await message.delete() -     peer = await client.resolve_peer(message.chat.id) -     request = functions.messages.ReadMentions(peer=peer) -     await client.send(request) - - - @Client.on_message(filters.command(["clear_all_@"], prefix) & filters.me) - async def global_mention_clear(client: Client, message: Message): -     request = functions.messages.GetAllChats(except_ids=[]) -     try: -         result = await client.send(request) -     except FloodWait as e: -         await message.edit_text( -             f"FloodWait received. Wait {e.x} seconds before trying again" -         ) -         return -     await message.delete() -     for chat in result.chats: -         if type(chat) is types.Chat: -             peer_id = -chat.id -         elif type(chat) is types.Channel: -             peer_id = int(f"-100{chat.id}") -         peer = await client.resolve_peer(peer_id) -         request = functions.messages.ReadMentions(peer=peer) -         await client.send(request) - - - @Client.on_message(filters.command(["clear_reacts"], prefix) & filters.me) - async def solo_reaction_clear(client: Client, message: Message): -     await message.delete() -     peer = await client.resolve_peer(message.chat.id) -     request = functions.messages.ReadReactions(peer=peer) -     await client.send(request) - - - @Client.on_message(filters.command(["clear_all_reacts"], prefix) & filters.me) - async def global_reaction_clear(client: Client, message: Message): -     request = functions.messages.GetAllChats(except_ids=[]) -     try: -         result = await client.send(request) -     except FloodWait as e: -         await message.edit_text( -             f"FloodWait received. Wait {e.x} seconds before trying again" -         ) -         return -     await message.delete() -     for chat in result.chats: -         if type(chat) is types.Chat: -             peer_id = -chat.id -         elif type(chat) is types.Channel: -             peer_id = int(f"-100{chat.id}") -         peer = await client.resolve_peer(peer_id) -         request = functions.messages.ReadReactions(peer=peer) -         await client.send(request) - - - modules_help["clear_notifs"] = { -     "clear_@": "clear all mentions in this chat", -     "clear_all_@": "clear all mentions in all chats", -     "clear_reacts": "clear all reactions in this chat", -     "clear_all_reacts": "clear all reactions in all chats (except private chats)", - } \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from pyrogram import Client, filters +from pyrogram.errors import FloodWait +from pyrogram.raw import functions, types +from pyrogram.types import Message + +from utils.misc import modules_help, prefix + + +@Client.on_message(filters.command(["clear_@"], prefix) & filters.me) +async def solo_mention_clear(client: Client, message: Message): + await message.delete() + peer = await client.resolve_peer(message.chat.id) + request = functions.messages.ReadMentions(peer=peer) + await client.send(request) + + +@Client.on_message(filters.command(["clear_all_@"], prefix) & filters.me) +async def global_mention_clear(client: Client, message: Message): + request = functions.messages.GetAllChats(except_ids=[]) + try: + result = await client.send(request) + except FloodWait as e: + await message.edit_text( + f"FloodWait received. Wait {e.x} seconds before trying again" + ) + return + await message.delete() + for chat in result.chats: + if type(chat) is types.Chat: + peer_id = -chat.id + elif type(chat) is types.Channel: + peer_id = int(f"-100{chat.id}") + peer = await client.resolve_peer(peer_id) + request = functions.messages.ReadMentions(peer=peer) + await client.send(request) + + +@Client.on_message(filters.command(["clear_reacts"], prefix) & filters.me) +async def solo_reaction_clear(client: Client, message: Message): + await message.delete() + peer = await client.resolve_peer(message.chat.id) + request = functions.messages.ReadReactions(peer=peer) + await client.send(request) + + +@Client.on_message(filters.command(["clear_all_reacts"], prefix) & filters.me) +async def global_reaction_clear(client: Client, message: Message): + request = functions.messages.GetAllChats(except_ids=[]) + try: + result = await client.send(request) + except FloodWait as e: + await message.edit_text( + f"FloodWait received. Wait {e.x} seconds before trying again" + ) + return + await message.delete() + for chat in result.chats: + if type(chat) is types.Chat: + peer_id = -chat.id + elif type(chat) is types.Channel: + peer_id = int(f"-100{chat.id}") + peer = await client.resolve_peer(peer_id) + request = functions.messages.ReadReactions(peer=peer) + await client.send(request) + + +modules_help["clear_notifs"] = { + "clear_@": "clear all mentions in this chat", + "clear_all_@": "clear all mentions in all chats", + "clear_reacts": "clear all reactions in this chat", + "clear_all_reacts": "clear all reactions in all chats (except private chats)", +} diff --git a/modules/example.py b/modules/example.py index 32e6528..5dbdeb6 100644 --- a/modules/example.py +++ b/modules/example.py @@ -1,53 +1,53 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - from pyrogram import Client, filters - from pyrogram.types import Message - - from utils.misc import modules_help, prefix - - - # if your module has packages from PyPi - - # from utils.scripts import import_library - # example_1 = import_library("example_1") - # example_2 = import_library("example_2") - - # import_library() will automatically install required library - # if it isn't installed - - - @Client.on_message(filters.command("example_edit", prefix) & filters.me) - async def example_edit(client: Client, message: Message): -     await message.edit("This is an example module") - - - @Client.on_message(filters.command("example_send", prefix) & filters.me) - async def example_send(client: Client, message: Message): -     await client.send_message(message.chat.id, "This is an example module") - - - # This adds instructions for your module - modules_help["example"] = { -     "example_send": "example send", -     "example_edit": "example edit", - } - - # modules_help["example"] = { "example_send [text]": "example send" } - #                  |            |              |        | - #                  |            |              |        └─ command description - #           module_name         command_name   └─ optional command arguments - #        (only snake_case)   (only snake_case too) +#  Moon-Userbot - telegram userbot +#  Copyright (C) 2020-present Moon Userbot Organization +# +#  This program is free software: you can redistribute it and/or modify +#  it under the terms of the GNU General Public License as published by +#  the Free Software Foundation, either version 3 of the License, or +#  (at your option) any later version. + +#  This program is distributed in the hope that it will be useful, +#  but WITHOUT ANY WARRANTY; without even the implied warranty of +#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#  GNU General Public License for more details. + +#  You should have received a copy of the GNU General Public License +#  along with this program.  If not, see . + +from pyrogram import Client, filters +from pyrogram.types import Message + +from utils.misc import modules_help, prefix + + +# if your module has packages from PyPi + +# from utils.scripts import import_library +# example_1 = import_library("example_1") +# example_2 = import_library("example_2") + +# import_library() will automatically install required library +# if it isn't installed + + +@Client.on_message(filters.command("example_edit", prefix) & filters.me) +async def example_edit(client: Client, message: Message): + await message.edit("This is an example module") + + +@Client.on_message(filters.command("example_send", prefix) & filters.me) +async def example_send(client: Client, message: Message): + await client.send_message(message.chat.id, "This is an example module") + + +# This adds instructions for your module +modules_help["example"] = { + "example_send": "example send", + "example_edit": "example edit", +} + +# modules_help["example"] = { "example_send [text]": "example send" } +# | | | | +# | | | └─ command description +# module_name command_name └─ optional command arguments +# (only snake_case) (only snake_case too) diff --git a/modules/filters.py b/modules/filters.py index 18f26d4..69f5d0a 100644 --- a/modules/filters.py +++ b/modules/filters.py @@ -1,3 +1,19 @@ +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + from pyrogram import Client, filters, ContinuePropagation, errors from pyrogram.types import ( Message, @@ -7,282 +23,256 @@ from pyrogram.types import ( InputMediaAudio, ) -# noinspection PyUnresolvedReferences +# noinspection PyUnresolvedReferences from utils.misc import modules_help, prefix from utils.scripts import format_exc -# noinspection PyUnresolvedReferences +# noinspection PyUnresolvedReferences from utils.db import db def get_filters_chat(chat_id): -return db.get("core.filters", f" { - chat_id -}", {}) + return db.get("core.filters", f"{chat_id}", {}) def set_filters_chat(chat_id, filters_): -return db.set("core.filters", f" { - chat_id -}", filters_) + return db.set("core.filters", f"{chat_id}", filters_) async def contains_filter(_, __, m): -return m.text and m.text.lower() in get_filters_chat(m.chat.id).keys() + return m.text and m.text.lower() in get_filters_chat(m.chat.id).keys() contains = filters.create(contains_filter) -# noinspection PyTypeChecker +# noinspection PyTypeChecker @Client.on_message(contains) async def filters_main_handler(client: Client, message: Message): -value = get_filters_chat(message.chat.id)[message.text.lower()] -try: -await client.get_messages(int(value["CHAT_ID"]), int(value["MESSAGE_ID"])) -except errors.RPCError: -raise ContinuePropagation + value = get_filters_chat(message.chat.id)[message.text.lower()] + try: + await client.get_messages(int(value["CHAT_ID"]), int(value["MESSAGE_ID"])) + except errors.RPCError: + raise ContinuePropagation -if value.get("MEDIA_GROUP"): -messages_grouped = await client.get_media_group( - int(value["CHAT_ID"]), int(value["MESSAGE_ID"]) -) -media_grouped_list = [] -for _ in messages_grouped: -if _.photo: -if _.caption: -media_grouped_list.append( - InputMediaPhoto(_.photo.file_id, _.caption.markdown) -) -else : -media_grouped_list.append(InputMediaPhoto(_.photo.file_id)) -elif _.video: -if _.caption: -if _.video.thumbs: -media_grouped_list.append( - InputMediaVideo( - _.video.file_id, - _.video.thumbs[0].file_id, - _.caption.markdown, - ) -) -else : -media_grouped_list.append( - InputMediaVideo(_.video.file_id, _.caption.markdown) -) -elif _.video.thumbs: -media_grouped_list.append( - InputMediaVideo(_.video.file_id, _.video.thumbs[0].file_id) -) -else : -media_grouped_list.append(InputMediaVideo(_.video.file_id)) -elif _.audio: -if _.caption: -media_grouped_list.append( - InputMediaAudio(_.audio.file_id, _.caption.markdown) -) -else : -media_grouped_list.append(InputMediaAudio(_.audio.file_id)) -elif _.document: -if _.caption: -if _.document.thumbs: -media_grouped_list.append( - InputMediaDocument( - _.document.file_id, - _.document.thumbs[0].file_id, - _.caption.markdown, - ) -) -else : -media_grouped_list.append( - InputMediaDocument(_.document.file_id, _.caption.markdown) -) -elif _.document.thumbs: -media_grouped_list.append( - InputMediaDocument( - _.document.file_id, _.document.thumbs[0].file_id - ) -) -else : -media_grouped_list.append(InputMediaDocument(_.document.file_id)) -await client.send_media_group( - message.chat.id, - media_grouped_list, - reply_to_message_id = message.message_id, -) -else : -await client.copy_message( - message.chat.id, - int(value["CHAT_ID"]), - int(value["MESSAGE_ID"]), - reply_to_message_id = message.message_id, -) -raise ContinuePropagation + if value.get("MEDIA_GROUP"): + messages_grouped = await client.get_media_group( + int(value["CHAT_ID"]), int(value["MESSAGE_ID"]) + ) + media_grouped_list = [] + for _ in messages_grouped: + if _.photo: + if _.caption: + media_grouped_list.append( + InputMediaPhoto(_.photo.file_id, _.caption.markdown) + ) + else: + media_grouped_list.append(InputMediaPhoto(_.photo.file_id)) + elif _.video: + if _.caption: + if _.video.thumbs: + media_grouped_list.append( + InputMediaVideo( + _.video.file_id, + _.video.thumbs[0].file_id, + _.caption.markdown, + ) + ) + else: + media_grouped_list.append( + InputMediaVideo(_.video.file_id, + _.caption.markdown) + ) + elif _.video.thumbs: + media_grouped_list.append( + InputMediaVideo(_.video.file_id, + _.video.thumbs[0].file_id) + ) + else: + media_grouped_list.append(InputMediaVideo(_.video.file_id)) + elif _.audio: + if _.caption: + media_grouped_list.append( + InputMediaAudio(_.audio.file_id, _.caption.markdown) + ) + else: + media_grouped_list.append(InputMediaAudio(_.audio.file_id)) + elif _.document: + if _.caption: + if _.document.thumbs: + media_grouped_list.append( + InputMediaDocument( + _.document.file_id, + _.document.thumbs[0].file_id, + _.caption.markdown, + ) + ) + else: + media_grouped_list.append( + InputMediaDocument( + _.document.file_id, _.caption.markdown) + ) + elif _.document.thumbs: + media_grouped_list.append( + InputMediaDocument( + _.document.file_id, _.document.thumbs[0].file_id + ) + ) + else: + media_grouped_list.append( + InputMediaDocument(_.document.file_id)) + await client.send_media_group( + message.chat.id, + media_grouped_list, + reply_to_message_id=message.message_id, + ) + else: + await client.copy_message( + message.chat.id, + int(value["CHAT_ID"]), + int(value["MESSAGE_ID"]), + reply_to_message_id=message.message_id, + ) + raise ContinuePropagation @Client.on_message(filters.command(["filter"], prefix) & filters.me) async def filter_handler(client: Client, message: Message): -try: -if len(message.text.split()) < 2: -return await message.edit( -f"Usage { - prefix -}filter [name] (Reply required)" -) -name = message.text.split(maxsplit = 1)[1].lower() -chat_filters = get_filters_chat(message.chat.id) -if name in chat_filters.keys(): -return await message.edit( -f"Filter  { - name -} already exists." -) -if not message.reply_to_message: -return await message.edit("Reply to message please.") + try: + if len(message.text.split()) < 2: + return await message.edit( + f"Usage: {prefix}filter [name] (Reply required)" + ) + name = message.text.split(maxsplit=1)[1].lower() + chat_filters = get_filters_chat(message.chat.id) + if name in chat_filters.keys(): + return await message.edit( + f"Filter {name} already exists." + ) + if not message.reply_to_message: + return await message.edit("Reply to message please.") -try: -chat = await client.get_chat(db.get("core.notes", "chat_id", 0)) -except (errors.RPCError, ValueError, KeyError): -# group is not accessible or isn't created -chat = await client.create_supergroup( - "Moon_Userbot_Notes_Filters", "Don't touch this group, please" -) -db.set("core.notes", "chat_id", chat.id) + try: + chat = await client.get_chat(db.get("core.notes", "chat_id", 0)) + except (errors.RPCError, ValueError, KeyError): + # group is not accessible or isn't created + chat = await client.create_supergroup( + "Moon_Userbot_Notes_Filters", "Don't touch this group, please" + ) + db.set("core.notes", "chat_id", chat.id) -chat_id = chat.id + chat_id = chat.id -if message.reply_to_message.media_group_id: -get_media_group = [ - _.message_id - for _ in await client.get_media_group( - message.chat.id, message.reply_to_message.message_id - ) -] -try: -message_id = await client.forward_messages( - chat_id, message.chat.id, get_media_group -) -except errors.ChatForwardsRestricted: -await message.edit( - "Forwarding messages is restricted by chat admins" -) -return -filter_ = { - "MESSAGE_ID": str(message_id[1].message_id), - "MEDIA_GROUP": True, - "CHAT_ID": str(chat_id), -} else : -try: -message_id = await message.reply_to_message.forward(chat_id) -except errors.ChatForwardsRestricted: -if message.reply_to_message.text: -# manual copy -message_id = await client.send_message( - chat_id, message.reply_to_message.text -) -else : -await message.edit( - "Forwarding messages is restricted by chat admins" -) -return -filter_ = { - "MEDIA_GROUP": False, - "MESSAGE_ID": str(message_id.message_id), - "CHAT_ID": str(chat_id), -} + if message.reply_to_message.media_group_id: + get_media_group = [ + _.message_id + for _ in await client.get_media_group( + message.chat.id, message.reply_to_message.message_id + ) + ] + try: + message_id = await client.forward_messages( + chat_id, message.chat.id, get_media_group + ) + except errors.ChatForwardsRestricted: + await message.edit( + "Forwarding messages is restricted by chat admins" + ) + return + filter_ = { + "MESSAGE_ID": str(message_id[1].message_id), + "MEDIA_GROUP": True, + "CHAT_ID": str(chat_id), + } + else: + try: + message_id = await message.reply_to_message.forward(chat_id) + except errors.ChatForwardsRestricted: + if message.reply_to_message.text: + # manual copy + message_id = await client.send_message( + chat_id, message.reply_to_message.text + ) + else: + await message.edit( + "Forwarding messages is restricted by chat admins" + ) + return + filter_ = { + "MEDIA_GROUP": False, + "MESSAGE_ID": str(message_id.message_id), + "CHAT_ID": str(chat_id), + } -chat_filters.update({ - name: filter_ -}) + chat_filters.update({name: filter_}) -set_filters_chat(message.chat.id, chat_filters) -return await message.edit(f"Filter  { - name -} has been added.") -except Exception as e: -return await message.edit(format_exc(e)) + set_filters_chat(message.chat.id, chat_filters) + return await message.edit(f"Filter {name} has been added.") + except Exception as e: + return await message.edit(format_exc(e)) @Client.on_message(filters.command(["filters"], prefix) & filters.me) async def filters_handler(client: Client, message: Message): -try: -text = "" -for index, a in enumerate(get_filters_chat(message.chat.id).items(), start = 1): -key, item = a -key = key.replace("<", "").replace(">", "") -text += f" { - index -}.  { - key -}\n" -text = f"Your filters in current chat:\n\n" f" { - text -}" -text = text[:4096] -return await message.edit(text) -except Exception as e: -return await message.edit(format_exc(e)) + try: + text = "" + for index, a in enumerate(get_filters_chat(message.chat.id).items(), start=1): + key, item = a + key = key.replace("<", "").replace(">", "") + text += f"{index}. {key}\n" + text = f"Your filters in current chat:\n\n" f"{text}" + text = text[:4096] + return await message.edit(text) + except Exception as e: + return await message.edit(format_exc(e)) @Client.on_message( filters.command(["delfilter", "filterdel", "fdel"], prefix) & filters.me ) async def filter_del_handler(client: Client, message: Message): -try: -if len(message.text.split()) < 2: -return await message.edit(f"Usage { - prefix -}fdel [name]") -name = message.text.split(maxsplit = 1)[1].lower() -chat_filters = get_filters_chat(message.chat.id) -if name not in chat_filters.keys(): -return await message.edit( -f"Filter  { - name -} doesn't exists." -) -del chat_filters[name] -set_filters_chat(message.chat.id, chat_filters) -return await message.edit( -f"Filter  { - name -} has been deleted." -) -except Exception as e: -return await message.edit(format_exc(e)) + try: + if len(message.text.split()) < 2: + return await message.edit(f"Usage: {prefix}fdel [name]") + name = message.text.split(maxsplit=1)[1].lower() + chat_filters = get_filters_chat(message.chat.id) + if name not in chat_filters.keys(): + return await message.edit( + f"Filter {name} doesn't exists." + ) + del chat_filters[name] + set_filters_chat(message.chat.id, chat_filters) + return await message.edit( + f"Filter {name} has been deleted." + ) + except Exception as e: + return await message.edit(format_exc(e)) @Client.on_message(filters.command(["fsearch"], prefix) & filters.me) async def filter_search_handler(client: Client, message: Message): -try: -if len(message.text.split()) < 2: -return await message.edit( -f"Usage { - prefix -}fsearch [name]" -) -name = message.text.split(maxsplit = 1)[1].lower() -chat_filters = get_filters_chat(message.chat.id) -if name not in chat_filters.keys(): -return await message.edit( -f"Filter  { - name -} doesn't exists." -) -return await message.edit( -f"Trigger:\n { - name -}\nAnswer:\n { - chat_filters[name]}" -) -except Exception as e: -return await message.edit(format_exc(e)) + try: + if len(message.text.split()) < 2: + return await message.edit( + f"Usage: {prefix}fsearch [name]" + ) + name = message.text.split(maxsplit=1)[1].lower() + chat_filters = get_filters_chat(message.chat.id) + if name not in chat_filters.keys(): + return await message.edit( + f"Filter {name} doesn't exists." + ) + return await message.edit( + f"Trigger:\n{name}\nAnswer:\n{chat_filters[name]}" + ) + except Exception as e: + return await message.edit(format_exc(e)) modules_help["filters"] = { - "filter [name]": "Create filter (Reply required)", - "filters": "List of all triggers", - "fdel [name]": "Delete filter by name", - "fsearch [name]": "Info filter by name", -} \ No newline at end of file + "filter [name]": "Create filter (Reply required)", + "filters": "List of all triggers", + "fdel [name]": "Delete filter by name", + "fsearch [name]": "Info filter by name", +} diff --git a/modules/help.py b/modules/help.py index 9b5ddda..2bce099 100644 --- a/modules/help.py +++ b/modules/help.py @@ -1,18 +1,18 @@ -#  Moon-Userbot - telegram userbot -#  Copyright (C) 2020-present Moon Userbot Organization +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization # -#  This program is free software: you can redistribute it and/or modify -#  it under the terms of the GNU General Public License as published by -#  the Free Software Foundation, either version 3 of the License, or -#  (at your option) any later version. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. -#  You should have received a copy of the GNU General Public License -#  along with this program.  If not, see . +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . from pyrogram import Client, filters from pyrogram.types import Message @@ -23,83 +23,58 @@ from utils.scripts import format_module_help @Client.on_message(filters.command(["help", "h"], prefix) & filters.me) async def help_cmd(_, message: Message): -if len(message.command) == 1: -msg_edited = False -text = ( - "Help for Moon-Userbot\n" -f"For more help on how to use a command, type  { - prefix - }help [module]\n\n" - "Available Modules:\n" -) + if len(message.command) == 1: + msg_edited = False + text = ( + "Help for Moon-Userbot\n" + f"For more help on how to use a command, type {prefix}help [module]\n\n" + "Available Modules:\n" + ) -for module_name, module_commands in modules_help.items(): -text += "• {}: {}\n".format( - module_name.title(), - " ".join( - [ -f" { - prefix + cmd_name.split()[0]}" - for cmd_name in module_commands.keys() - ] - ), -) -if len(text) >= 2048: -text += "" -if msg_edited: -await message.reply(text, disable_web_page_preview = True) -else : -await message.edit(text, disable_web_page_preview = True) -msg_edited = True -text = "" + for module_name, module_commands in modules_help.items(): + text += "• {}: {}\n".format( + module_name.title(), + " ".join( + [ + f"{prefix + cmd_name.split()[0]}" + for cmd_name in module_commands.keys() + ] + ), + ) + if len(text) >= 2048: + text += "" + if msg_edited: + await message.reply(text, disable_web_page_preview=True) + else: + await message.edit(text, disable_web_page_preview=True) + msg_edited = True + text = "" -text += f"\nThe number of modules in the userbot:  { - len(modules_help) / 1 -}" + text += f"\nThe number of modules in the userbot: {len(modules_help) / 1}" -if msg_edited: -await message.reply(text, disable_web_page_preview = True) -else : -await message.edit(text, disable_web_page_preview = True) -elif message.command[1].lower() in modules_help: -await message.edit(format_module_help(message.command[1].lower())) -else : -# TODO: refactor this cringe -command_name = message.command[1].lower() -for name, commands in modules_help.items(): -for command in commands.keys(): -if command.split()[0] == command_name: -cmd = command.split(maxsplit = 1) -cmd_desc = commands[command] -return await message.edit( -f"Help for command  { - prefix -} { - command_name -}\n" -f"Module:  { - name -} ( { - prefix -}help  { - name -})\n\n" -f" { - prefix -} { - cmd[0]}" -f" { - ' ' + cmd[1] + '' if len(cmd) > 1 else '' -}" -f" —  { - cmd_desc -}" -) -await message.edit(f"Module  { - command_name -} not found") + if msg_edited: + await message.reply(text, disable_web_page_preview=True) + else: + await message.edit(text, disable_web_page_preview=True) + elif message.command[1].lower() in modules_help: + await message.edit(format_module_help(message.command[1].lower())) + else: + # TODO: refactor this cringe + command_name = message.command[1].lower() + for name, commands in modules_help.items(): + for command in commands.keys(): + if command.split()[0] == command_name: + cmd = command.split(maxsplit=1) + cmd_desc = commands[command] + return await message.edit( + f"Help for command {prefix}{command_name}\n" + f"Module: {name} ({prefix}help {name})\n\n" + f"{prefix}{cmd[0]}" + f"{' ' + cmd[1] + '' if len(cmd) > 1 else ''}" + f" — {cmd_desc}" + ) + await message.edit(f"Module {command_name} not found") modules_help["help"] = { - "help [module/command name]": "Get common/module/command help" -} \ No newline at end of file + "help [module/command name]": "Get common/module/command help"} diff --git a/modules/loader.py b/modules/loader.py index 93498ce..a4a3115 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -1,225 +1,225 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - import hashlib - import os - - import requests - from pyrogram import Client, filters - from pyrogram.types import Message - - from utils.scripts import restart - from utils.misc import modules_help, prefix - - - BASE_PATH = os.path.abspath(os.getcwd()) - - - @Client.on_message(filters.command(["modhash", "mh"], prefix) & filters.me) - async def get_mod_hash(_, message: Message): -     if len(message.command) == 1: -         return -     url = message.command[1].lower() -     resp = requests.get(url) -     if not resp.ok: -         await message.edit( -             f"Troubleshooting with downloading module {url}" -         ) -         return - -     await message.edit( -         f"Module hash: {hashlib.sha256(resp.content).hexdigest()}\n" -         f"Link: {url}\nFile: {url.split('/')[-1]}" -     ) - - - @Client.on_message(filters.command(["loadmod", "lm"], prefix) & filters.me) - async def loadmod(_, message: Message): -     if ( -         not ( -             message.reply_to_message -             and message.reply_to_message.document -             and message.reply_to_message.document.file_name.endswith(".py") -         ) -         and len(message.command) == 1 -     ): -         await message.edit("Specify module to download") -         return - -     if len(message.command) > 1: -         url = message.command[1].lower() - -         if url.startswith( -             "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" -         ): -             module_name = url.split("/")[-1].split(".")[0] -         elif "/" not in url and "." not in url: -             module_name = url.lower() -             url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py" -         else: -             modules_hashes = requests.get( -                 "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" -             ).text -             resp = requests.get(url) - -             if not resp.ok: -                 await message.edit( -                     f"Troubleshooting with downloading module {url}" -                 ) -                 return - -             if hashlib.sha256(resp.content).hexdigest() not in modules_hashes: -                 return await message.edit( -                     "Only " -                     "verified modules or from the official " -                     "" -                     "custom_modules repository are supported!", -                     disable_web_page_preview=True, -                 ) - -             module_name = url.split("/")[-1].split(".")[0] - -         resp = requests.get(url) -         if not resp.ok: -             await message.edit(f"Module {module_name} is not found") -             return - -         if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): -             os.mkdir(f"{BASE_PATH}/modules/custom_modules") - -         with open(f"./modules/custom_modules/{module_name}.py", "wb") as f: -             f.write(resp.content) -     else: -         file_name = await message.reply_to_message.download() -         module_name = message.reply_to_message.document.file_name[:-3] - -         with open(file_name, "rb") as f: -             content = f.read() - -         modules_hashes = requests.get( -             "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" -         ).text - -         if hashlib.sha256(content).hexdigest() not in modules_hashes: -             os.remove(file_name) -             return await message.edit( -                 "Only " -                 "verified modules or from the official " -                 "" -                 "custom_modules repository are supported!", -                 disable_web_page_preview=True, -             ) -         else: -             os.rename(file_name, f"./modules/custom_modules/{module_name}.py") - -     await message.edit(f"The module {module_name} is loaded!") -     restart() - - - @Client.on_message(filters.command(["unloadmod", "ulm"], prefix) & filters.me) - async def unload_mods(_, message: Message): -     if len(message.command) <= 1: -         return - -     module_name = message.command[1].lower() - -     if module_name.startswith( -         "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" -     ): -         module_name = module_name.split("/")[-1].split(".")[0] - -     if os.path.exists(f"{BASE_PATH}/modules/custom_modules/{module_name}.py"): -         os.remove(f"{BASE_PATH}/modules/custom_modules/{module_name}.py") -         await message.edit(f"The module {module_name} removed!") -         restart() -     elif os.path.exists(f"{BASE_PATH}/modules/{module_name}.py"): -         await message.edit( -             "It is forbidden to remove built-in modules, it will disrupt the updater" -         ) -     else: -         await message.edit(f"Module {module_name} is not found") - - - @Client.on_message(filters.command(["loadallmods"], prefix) & filters.me) - async def load_all_mods(_, message: Message): -     await message.edit("Fetching info...") - -     if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): -         os.mkdir(f"{BASE_PATH}/modules/custom_modules") - -     modules_list = requests.get( -         "https://api.github.com/repos/The-MoonTg-project/custom_modules/contents/" -     ).json() - -     new_modules = {} -     for module_info in modules_list: -         if not module_info["name"].endswith(".py"): -             continue -         if os.path.exists(f'{BASE_PATH}/modules/custom_modules/{module_info["name"]}'): -             continue -         new_modules[module_info["name"][:-3]] = module_info["download_url"] -     if not new_modules: -         return await message.edit("All modules already loaded") - -     await message.edit(f'Loading new modules: {" ".join(new_modules.keys())}') -     for name, url in new_modules.items(): -         with open(f"./modules/custom_modules/{name}.py", "wb") as f: -             f.write(requests.get(url).content) - -     await message.edit( -         f'Successfully loaded new modules: {" ".join(new_modules.keys())}' -     ) -     restart() - - - @Client.on_message(filters.command(["updateallmods"], prefix) & filters.me) - async def updateallmods(_, message: Message): -     await message.edit("Updating modules...") - -     if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): -         os.mkdir(f"{BASE_PATH}/modules/custom_modules") - -     modules_installed = list(os.walk("modules/custom_modules"))[0][2] - -     if not modules_installed: -         return await message.edit("You don't have any modules installed") - -     for module_name in modules_installed: -         if not module_name.endswith(".py"): -             continue - -         resp = requests.get( -             f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}" -         ) -         if not resp.ok: -             modules_installed.remove(module_name) -             continue - -         with open(f"./modules/custom_modules/{module_name}", "wb") as f: -             f.write(resp.content) - -     await message.edit(f"Successfully updated {len(modules_installed)} modules") - - - modules_help["loader"] = { -     "loadmod [module_name]*": "Download module.\n" -     "Only modules from the official custom_modules repository and proven " -     "modules whose hashes are in modules_hashes.txt are supported", -     "unloadmod [module_name]*": "Delete module", -     "modhash [link]*": "Get module hash by link", -     "loadallmods": "Load all custom modules (use it at your own risk)", -     "updateallmods": "Update all custom modules", - } \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import hashlib +import os + +import requests +from pyrogram import Client, filters +from pyrogram.types import Message + +from utils.scripts import restart +from utils.misc import modules_help, prefix + + +BASE_PATH = os.path.abspath(os.getcwd()) + + +@Client.on_message(filters.command(["modhash", "mh"], prefix) & filters.me) +async def get_mod_hash(_, message: Message): + if len(message.command) == 1: + return + url = message.command[1].lower() + resp = requests.get(url) + if not resp.ok: + await message.edit( + f"Troubleshooting with downloading module {url}" + ) + return + + await message.edit( + f"Module hash: {hashlib.sha256(resp.content).hexdigest()}\n" + f"Link: {url}\nFile: {url.split('/')[-1]}" + ) + + +@Client.on_message(filters.command(["loadmod", "lm"], prefix) & filters.me) +async def loadmod(_, message: Message): + if ( + not ( + message.reply_to_message + and message.reply_to_message.document + and message.reply_to_message.document.file_name.endswith(".py") + ) + and len(message.command) == 1 + ): + await message.edit("Specify module to download") + return + + if len(message.command) > 1: + url = message.command[1].lower() + + if url.startswith( + "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" + ): + module_name = url.split("/")[-1].split(".")[0] + elif "/" not in url and "." not in url: + module_name = url.lower() + url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py" + else: + modules_hashes = requests.get( + "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" + ).text + resp = requests.get(url) + + if not resp.ok: + await message.edit( + f"Troubleshooting with downloading module {url}" + ) + return + + if hashlib.sha256(resp.content).hexdigest() not in modules_hashes: + return await message.edit( + "Only " + "verified modules or from the official " + "" + "custom_modules repository are supported!", + disable_web_page_preview=True, + ) + + module_name = url.split("/")[-1].split(".")[0] + + resp = requests.get(url) + if not resp.ok: + await message.edit(f"Module {module_name} is not found") + return + + if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): + os.mkdir(f"{BASE_PATH}/modules/custom_modules") + + with open(f"./modules/custom_modules/{module_name}.py", "wb") as f: + f.write(resp.content) + else: + file_name = await message.reply_to_message.download() + module_name = message.reply_to_message.document.file_name[:-3] + + with open(file_name, "rb") as f: + content = f.read() + + modules_hashes = requests.get( + "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" + ).text + + if hashlib.sha256(content).hexdigest() not in modules_hashes: + os.remove(file_name) + return await message.edit( + "Only " + "verified modules or from the official " + "" + "custom_modules repository are supported!", + disable_web_page_preview=True, + ) + else: + os.rename(file_name, f"./modules/custom_modules/{module_name}.py") + + await message.edit(f"The module {module_name} is loaded!") + restart() + + +@Client.on_message(filters.command(["unloadmod", "ulm"], prefix) & filters.me) +async def unload_mods(_, message: Message): + if len(message.command) <= 1: + return + + module_name = message.command[1].lower() + + if module_name.startswith( + "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" + ): + module_name = module_name.split("/")[-1].split(".")[0] + + if os.path.exists(f"{BASE_PATH}/modules/custom_modules/{module_name}.py"): + os.remove(f"{BASE_PATH}/modules/custom_modules/{module_name}.py") + await message.edit(f"The module {module_name} removed!") + restart() + elif os.path.exists(f"{BASE_PATH}/modules/{module_name}.py"): + await message.edit( + "It is forbidden to remove built-in modules, it will disrupt the updater" + ) + else: + await message.edit(f"Module {module_name} is not found") + + +@Client.on_message(filters.command(["loadallmods"], prefix) & filters.me) +async def load_all_mods(_, message: Message): + await message.edit("Fetching info...") + + if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): + os.mkdir(f"{BASE_PATH}/modules/custom_modules") + + modules_list = requests.get( + "https://api.github.com/repos/The-MoonTg-project/custom_modules/contents/" + ).json() + + new_modules = {} + for module_info in modules_list: + if not module_info["name"].endswith(".py"): + continue + if os.path.exists(f'{BASE_PATH}/modules/custom_modules/{module_info["name"]}'): + continue + new_modules[module_info["name"][:-3]] = module_info["download_url"] + if not new_modules: + return await message.edit("All modules already loaded") + + await message.edit(f'Loading new modules: {" ".join(new_modules.keys())}') + for name, url in new_modules.items(): + with open(f"./modules/custom_modules/{name}.py", "wb") as f: + f.write(requests.get(url).content) + + await message.edit( + f'Successfully loaded new modules: {" ".join(new_modules.keys())}' + ) + restart() + + +@Client.on_message(filters.command(["updateallmods"], prefix) & filters.me) +async def updateallmods(_, message: Message): + await message.edit("Updating modules...") + + if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): + os.mkdir(f"{BASE_PATH}/modules/custom_modules") + + modules_installed = list(os.walk("modules/custom_modules"))[0][2] + + if not modules_installed: + return await message.edit("You don't have any modules installed") + + for module_name in modules_installed: + if not module_name.endswith(".py"): + continue + + resp = requests.get( + f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}" + ) + if not resp.ok: + modules_installed.remove(module_name) + continue + + with open(f"./modules/custom_modules/{module_name}", "wb") as f: + f.write(resp.content) + + await message.edit(f"Successfully updated {len(modules_installed)} modules") + + +modules_help["loader"] = { + "loadmod [module_name]*": "Download module.\n" + "Only modules from the official custom_modules repository and proven " + "modules whose hashes are in modules_hashes.txt are supported", + "unloadmod [module_name]*": "Delete module", + "modhash [link]*": "Get module hash by link", + "loadallmods": "Load all custom modules (use it at your own risk)", + "updateallmods": "Update all custom modules", +} diff --git a/termux-install.sh b/termux-install.sh index 08ec188..666fce7 100644 --- a/termux-install.sh +++ b/termux-install.sh @@ -29,7 +29,7 @@ if ! command -v termux-setup-storage; then echo echo "Enter API_ID and API_HASH" - echo "You can get it here -> https://my.telegram.org/apps" + echo "You can get it here -> https://my.telegram.org/" echo "Leave empty to use defaults  (please note that default keys significantly increases your ban chances)" read -r -p "API_ID > " api_id diff --git a/utils/db.py b/utils/db.py index 7ce5dd8..0787aa1 100644 --- a/utils/db.py +++ b/utils/db.py @@ -1,170 +1,170 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - import json - import threading - import dns.resolver - import pymongo - import sqlite3 - from utils import config - - dns.resolver.default_resolver = dns.resolver.Resolver(configure=False) - dns.resolver.default_resolver.nameservers = ["8.8.8.8"] - - - class Database: -     def get(self, module: str, variable: str, default=None): -         """Get value from database""" -         raise NotImplementedError - -     def set(self, module: str, variable: str, value): -         """Set key in database""" -         raise NotImplementedError - -     def remove(self, module: str, variable: str): -         """Remove key from database""" -         raise NotImplementedError - -     def get_collection(self, module: str) -> dict: -         """Get database for selected module""" -         raise NotImplementedError - -     def close(self): -         """Close the database""" -         raise NotImplementedError - - - class MongoDatabase(Database): -     def __init__(self, url, name): -         self._client = pymongo.MongoClient(url) -         self._database = self._client[name] - -     def set(self, module: str, variable: str, value): -         self._database[module].replace_one( -             {"var": variable}, {"var": variable, "val": value}, upsert=True -         ) - -     def get(self, module: str, variable: str, expected_value=None): -         doc = self._database[module].find_one({"var": variable}) -         return expected_value if doc is None else doc["val"] - -     def get_collection(self, module: str): -         return {item["var"]: item["val"] for item in self._database[module].find()} - -     def remove(self, module: str, variable: str): -         self._database[module].delete_one({"var": variable}) - -     def close(self): -         self._client.close() - - - class SqliteDatabase(Database): -     def __init__(self, file): -         self._conn = sqlite3.connect(file, check_same_thread=False) -         self._conn.row_factory = sqlite3.Row -         self._cursor = self._conn.cursor() -         self._lock = threading.Lock() - -     @staticmethod -     def _parse_row(row: sqlite3.Row): -         if row["type"] == "bool": -             return row["val"] == "1" -         elif row["type"] == "int": -             return int(row["val"]) -         elif row["type"] == "str": -             return row["val"] -         else: -             return json.loads(row["val"]) - -     def _execute(self, module: str, *args, **kwargs) -> sqlite3.Cursor: -         self._lock.acquire() -         try: -             return self._cursor.execute(*args, **kwargs) -         except sqlite3.OperationalError as e: -             if str(e).startswith("no such table"): -                 sql = f""" -                 CREATE TABLE IF NOT EXISTS '{module}' ( -                 var TEXT UNIQUE NOT NULL, -                 val TEXT NOT NULL, -                 type TEXT NOT NULL -                 ) -                 """ -                 self._cursor.execute(sql) -                 self._conn.commit() -                 return self._cursor.execute(*args, **kwargs) -             raise e from None -         finally: -             self._lock.release() - -     def get(self, module: str, variable: str, default=None): -         sql = f"SELECT * FROM '{module}' WHERE var=:var" -         cur = self._execute(module, sql, {"tabl": module, "var": variable}) - -         row = cur.fetchone() -         if row is None: -             return default -         else: -             return self._parse_row(row) - -     def set(self, module: str, variable: str, value) -> bool: -         sql = f""" -         INSERT INTO '{module}' VALUES ( :var, :val, :type ) -         ON CONFLICT (var) DO -         UPDATE SET val=:val, type=:type WHERE var=:var -         """ - -         if isinstance(value, bool): -             val = "1" if value else "0" -             typ = "bool" -         elif isinstance(value, str): -             val = value -             typ = "str" -         elif isinstance(value, int): -             val = str(value) -             typ = "int" -         else: -             val = json.dumps(value) -             typ = "json" - -         self._execute(module, sql, {"var": variable, "val": val, "type": typ}) -         self._conn.commit() - -         return True - -     def remove(self, module: str, variable: str): -         sql = f"DELETE FROM '{module}' WHERE var=:var" -         self._execute(module, sql, {"var": variable}) -         self._conn.commit() - -     def get_collection(self, module: str) -> dict: -         sql = f"SELECT * FROM '{module}'" -         cur = self._execute(module, sql) - -         collection = {} -         for row in cur: -             collection[row["var"]] = self._parse_row(row) - -         return collection - -     def close(self): -         self._conn.commit() -         self._conn.close() - - - if config.db_type in ["mongo", "mongodb"]: -     db = MongoDatabase(config.db_url, config.db_name) - else: -     db = SqliteDatabase(config.db_name) \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import json +import threading +import dns.resolver +import pymongo +import sqlite3 +from utils import config + +dns.resolver.default_resolver = dns.resolver.Resolver(configure=False) +dns.resolver.default_resolver.nameservers = ["8.8.8.8"] + + +class Database: + def get(self, module: str, variable: str, default=None): + """Get value from database""" + raise NotImplementedError + + def set(self, module: str, variable: str, value): + """Set key in database""" + raise NotImplementedError + + def remove(self, module: str, variable: str): + """Remove key from database""" + raise NotImplementedError + + def get_collection(self, module: str) -> dict: + """Get database for selected module""" + raise NotImplementedError + + def close(self): + """Close the database""" + raise NotImplementedError + + +class MongoDatabase(Database): + def __init__(self, url, name): + self._client = pymongo.MongoClient(url) + self._database = self._client[name] + + def set(self, module: str, variable: str, value): + self._database[module].replace_one( + {"var": variable}, {"var": variable, "val": value}, upsert=True + ) + + def get(self, module: str, variable: str, expected_value=None): + doc = self._database[module].find_one({"var": variable}) + return expected_value if doc is None else doc["val"] + + def get_collection(self, module: str): + return {item["var"]: item["val"] for item in self._database[module].find()} + + def remove(self, module: str, variable: str): + self._database[module].delete_one({"var": variable}) + + def close(self): + self._client.close() + + +class SqliteDatabase(Database): + def __init__(self, file): + self._conn = sqlite3.connect(file, check_same_thread=False) + self._conn.row_factory = sqlite3.Row + self._cursor = self._conn.cursor() + self._lock = threading.Lock() + + @staticmethod + def _parse_row(row: sqlite3.Row): + if row["type"] == "bool": + return row["val"] == "1" + elif row["type"] == "int": + return int(row["val"]) + elif row["type"] == "str": + return row["val"] + else: + return json.loads(row["val"]) + + def _execute(self, module: str, *args, **kwargs) -> sqlite3.Cursor: + self._lock.acquire() + try: + return self._cursor.execute(*args, **kwargs) + except sqlite3.OperationalError as e: + if str(e).startswith("no such table"): + sql = f""" + CREATE TABLE IF NOT EXISTS '{module}' ( + var TEXT UNIQUE NOT NULL, + val TEXT NOT NULL, + type TEXT NOT NULL + ) + """ + self._cursor.execute(sql) + self._conn.commit() + return self._cursor.execute(*args, **kwargs) + raise e from None + finally: + self._lock.release() + + def get(self, module: str, variable: str, default=None): + sql = f"SELECT * FROM '{module}' WHERE var=:var" + cur = self._execute(module, sql, {"tabl": module, "var": variable}) + + row = cur.fetchone() + if row is None: + return default + else: + return self._parse_row(row) + + def set(self, module: str, variable: str, value) -> bool: + sql = f""" + INSERT INTO '{module}' VALUES ( :var, :val, :type ) + ON CONFLICT (var) DO + UPDATE SET val=:val, type=:type WHERE var=:var + """ + + if isinstance(value, bool): + val = "1" if value else "0" + typ = "bool" + elif isinstance(value, str): + val = value + typ = "str" + elif isinstance(value, int): + val = str(value) + typ = "int" + else: + val = json.dumps(value) + typ = "json" + + self._execute(module, sql, {"var": variable, "val": val, "type": typ}) + self._conn.commit() + + return True + + def remove(self, module: str, variable: str): + sql = f"DELETE FROM '{module}' WHERE var=:var" + self._execute(module, sql, {"var": variable}) + self._conn.commit() + + def get_collection(self, module: str) -> dict: + sql = f"SELECT * FROM '{module}'" + cur = self._execute(module, sql) + + collection = {} + for row in cur: + collection[row["var"]] = self._parse_row(row) + + return collection + + def close(self): + self._conn.commit() + self._conn.close() + + +if config.db_type in ["mongo", "mongodb"]: + db = MongoDatabase(config.db_url, config.db_name) +else: + db = SqliteDatabase(config.db_name) diff --git a/utils/misc.py b/utils/misc.py index 0703f63..215fe2f 100644 --- a/utils/misc.py +++ b/utils/misc.py @@ -1,44 +1,45 @@ -#  Moon-Userbot - telegram userbot - #  Copyright (C) 2020-present Moon Userbot Organization - # - #  This program is free software: you can redistribute it and/or modify - #  it under the terms of the GNU General Public License as published by - #  the Free Software Foundation, either version 3 of the License, or - #  (at your option) any later version. - - #  This program is distributed in the hope that it will be useful, - #  but WITHOUT ANY WARRANTY; without even the implied warranty of - #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - #  GNU General Public License for more details. - - #  You should have received a copy of the GNU General Public License - #  along with this program.  If not, see . - - from sys import version_info - from .db import db - from git import Repo - - - class ModulesHelpDict(dict): -     def append(self, obj: dict): -         # convert help from old to new type -         module_name = list(obj.keys())[0] -         cmds = obj[module_name] -         commands = {} -         for cmd in cmds: -             cmd_name = list(cmd.keys())[0] -             cmd_desc = cmd[cmd_name] -             commands[cmd_name] = cmd_desc -         self[module_name] = commands - - - modules_help = ModulesHelpDict() - requirements_list = [] - - python_version = f"{version_info[0]}.{version_info[1]}.{version_info[2]}" - - prefix = db.get("core.main", "prefix", ".") - - gitrepo = Repo(".") - commits_since_tag = list(gitrepo.iter_commits(f"{gitrepo.tags[-1].name}..HEAD")) - userbot_version = f"3.1.{len(commits_since_tag)}" \ No newline at end of file +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from sys import version_info +from .db import db +from git import Repo + + +class ModulesHelpDict(dict): + def append(self, obj: dict): + # convert help from old to new type + module_name = list(obj.keys())[0] + cmds = obj[module_name] + commands = {} + for cmd in cmds: + cmd_name = list(cmd.keys())[0] + cmd_desc = cmd[cmd_name] + commands[cmd_name] = cmd_desc + self[module_name] = commands + + +modules_help = ModulesHelpDict() +requirements_list = [] + +python_version = f"{version_info[0]}.{version_info[1]}.{version_info[2]}" + +prefix = db.get("core.main", "prefix", ".") + +gitrepo = Repo(".") +commits_since_tag = list(gitrepo.iter_commits( + f"{gitrepo.tags[-1].name}..HEAD")) +userbot_version = f"3.1.{len(commits_since_tag)}" diff --git a/utils/scripts.py b/utils/scripts.py index e1cccba..dc98981 100644 --- a/utils/scripts.py +++ b/utils/scripts.py @@ -1,18 +1,18 @@ -#  Moon-Userbot - telegram userbot -#  Copyright (C) 2020-present Moon Userbot Organization +# Moon-Userbot - telegram userbot +# Copyright (C) 2020-present Moon Userbot Organization # -#  This program is free software: you can redistribute it and/or modify -#  it under the terms of the GNU General Public License as published by -#  the Free Software Foundation, either version 3 of the License, or -#  (at your option) any later version. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. -#  You should have received a copy of the GNU General Public License -#  along with this program.  If not, see . +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import asyncio import os import sys @@ -28,173 +28,137 @@ from .misc import modules_help, prefix, requirements_list def text(message: types.Message): -return message.text if message.text else message.caption + return message.text if message.text else message.caption def restart(): -os.execvp(sys.executable, [sys.executable, "main.py"]) + os.execvp(sys.executable, [sys.executable, "main.py"]) def format_exc(e: Exception, hint: str = None): -traceback.print_exc() -if isinstance(e, errors.RPCError): -return ( -f"Telegram API error!\n" -f"[ { - e.CODE -}  { - e.ID or e.NAME -}] -  { - e.MESSAGE -}" -) -else : -if hint: -hint_text = f"\n\nHint:  { - hint -}" -else : -hint_text = "" -return ( -f"Error!\n" f" { - e.__class__.__name__ -}:  { - e -}" + hint_text -) + traceback.print_exc() + if isinstance(e, errors.RPCError): + return ( + f"Telegram API error!\n" + f"[{e.CODE} {e.ID or e.NAME}] - {e.MESSAGE}" + ) + else: + if hint: + hint_text = f"\n\nHint: {hint}" + else: + hint_text = "" + return ( + f"Error!\n" f"{e.__class__.__name__}: {e}" + hint_text + ) def with_reply(func): -async def wrapped(client: Client, message: types.Message): -if not message.reply_to_message: -await message.edit("Reply to message is required") -else : -return await func(client, message) + async def wrapped(client: Client, message: types.Message): + if not message.reply_to_message: + await message.edit("Reply to message is required") + else: + return await func(client, message) -return wrapped + return wrapped async def interact_with(message: types.Message) -> types.Message: -""" -     Check history with bot and return bot's response -     Example: -     .. code-block:: python -         bot_msg = await interact_with(await bot.send_message("@BotFather", "/start")) -     :param message: already sent message to bot -     :return: bot's response -     """ + """ + Check history with bot and return bot's response + Example: + .. code-block:: python + bot_msg = await interact_with(await bot.send_message("@BotFather", "/start")) + :param message: already sent message to bot + :return: bot's response + """ -await asyncio.sleep(1) -# noinspection PyProtectedMember -response = await message._client.get_history(message.chat.id, limit = 1) -seconds_waiting = 0 + await asyncio.sleep(1) + # noinspection PyProtectedMember + response = await message._client.get_history(message.chat.id, limit=1) + seconds_waiting = 0 -while response[0].from_user.is_self: -seconds_waiting += 1 -if seconds_waiting >= 5: -raise RuntimeError("bot didn't answer in 5 seconds") + while response[0].from_user.is_self: + seconds_waiting += 1 + if seconds_waiting >= 5: + raise RuntimeError("bot didn't answer in 5 seconds") -await asyncio.sleep(1) -# noinspection PyProtectedMember -response = await message._client.get_history(message.chat.id, limit = 1) + await asyncio.sleep(1) + # noinspection PyProtectedMember + response = await message._client.get_history(message.chat.id, limit=1) -interact_with_to_delete.append(message.message_id) -interact_with_to_delete.append(response[0].message_id) + interact_with_to_delete.append(message.message_id) + interact_with_to_delete.append(response[0].message_id) -return response[0] + return response[0] interact_with_to_delete = [] def format_module_help(module_name: str): -commands = modules_help[module_name] + commands = modules_help[module_name] -help_text = f"Help for | { - module_name -}|\n\nUsage:\n" + help_text = f"Help for |{module_name}|\n\nUsage:\n" -for command, desc in commands.items(): -cmd = command.split(maxsplit = 1) -args = " " + cmd[1] + "" if len(cmd) > 1 else "" -help_text += f" { - prefix -} { - cmd[0]} { - args -} —  { - desc -}\n" + for command, desc in commands.items(): + cmd = command.split(maxsplit=1) + args = " " + cmd[1] + "" if len(cmd) > 1 else "" + help_text += f"{prefix}{cmd[0]}{args} — {desc}\n" -return help_text + return help_text def format_small_module_help(module_name: str): -commands = modules_help[module_name] + commands = modules_help[module_name] -help_text = f"Help for | { - module_name -}|\n\nCommands list:\n" -for command, desc in commands.items(): -cmd = command.split(maxsplit = 1) -args = " " + cmd[1] + "" if len(cmd) > 1 else "" -help_text += f" { - prefix -} { - cmd[0]} { - args -}\n" -help_text += f"\nGet full usage:  { - prefix -}help  { - module_name -}" + help_text = f"Help for |{module_name}|\n\nCommands list:\n" + for command, desc in commands.items(): + cmd = command.split(maxsplit=1) + args = " " + cmd[1] + "" if len(cmd) > 1 else "" + help_text += f"{prefix}{cmd[0]}{args}\n" + help_text += f"\nGet full usage: {prefix}help {module_name}" -return help_text + return help_text def import_library(library_name: str, package_name: str = None): -""" -     Loads a library, or installs it in ImportError case -     :param library_name: library name (import example...) -     :param package_name: package name in PyPi (pip install example) -     :return: loaded module -     """ -if package_name is None: -package_name = library_name -requirements_list.append(package_name) + """ + Loads a library, or installs it in ImportError case + :param library_name: library name (import example...) + :param package_name: package name in PyPi (pip install example) + :return: loaded module + """ + if package_name is None: + package_name = library_name + requirements_list.append(package_name) -try: -return importlib.import_module(library_name) -except ImportError: -completed = subprocess.run(["python3", "-m", "pip", "install", package_name]) -if completed.returncode != 0: -raise AssertionError( -f"Failed to install library  { - package_name -} (pip exited with code  { - completed.returncode -})" -) -return importlib.import_module(library_name) + try: + return importlib.import_module(library_name) + except ImportError: + completed = subprocess.run( + ["python3", "-m", "pip", "install", package_name]) + if completed.returncode != 0: + raise AssertionError( + f"Failed to install library {package_name} (pip exited with code {completed.returncode})" + ) + return importlib.import_module(library_name) -def resize_image(input_img, output = None, img_type = "PNG"): -if output is None: -output = BytesIO() -output.name = f"sticker. { - img_type.lower()}" +def resize_image(input_img, output=None, img_type="PNG"): + if output is None: + output = BytesIO() + output.name = f"sticker.{img_type.lower()}" -with Image.open(input_img) as img: -# We used to use thumbnail(size) here, but it returns with a *max* dimension of 512,512 -# rather than making one side exactly 512 so we have to calculate dimensions manually :( -if img.width == img.height: -size = (512, 512) -elif img.width < img.height: -size = (max(512 * img.width // img.height, 1), 512) -else : -size = (512, max(512 * img.height // img.width, 1)) + with Image.open(input_img) as img: + # We used to use thumbnail(size) here, but it returns with a *max* dimension of 512,512 + # rather than making one side exactly 512 so we have to calculate dimensions manually :( + if img.width == img.height: + size = (512, 512) + elif img.width < img.height: + size = (max(512 * img.width // img.height, 1), 512) + else: + size = (512, max(512 * img.height // img.width, 1)) -img.resize(size).save(output, img_type) + img.resize(size).save(output, img_type) -return output \ No newline at end of file + return output