This commit is contained in:
AbhiTheModder
2023-02-09 11:55:47 +05:30
parent e8087d9c93
commit 3e8520b0f5
17 changed files with 2888 additions and 2956 deletions

View File

@@ -14,7 +14,7 @@
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com)
</p> </p>
#### _A Simple, Fast, Customizable Userbot for Telegram._ #### _A Simple, Fast, Customizable Userbot for Telegram made after Dragon-Userbot abandoned._
<h1>Installation</h1> <h1>Installation</h1>

View File

@@ -1,18 +1,18 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import datetime import datetime
import sys import sys
@@ -21,51 +21,46 @@ from pyrogram import Client
from utils import config from utils import config
if __name__ == "__main__": if __name__ == "__main__":
app = Client( app = Client(
"my_account", "my_account",
api_id = config.api_id, api_id=config.api_id,
api_hash = config.api_hash, api_hash=config.api_hash,
hide_password = True, hide_password=True,
test_mode = config.test_server, test_mode=config.test_server,
) )
if config.db_type in ["mongo", "mongodb"]: if config.db_type in ["mongo", "mongodb"]:
from pymongo import MongoClient, errors from pymongo import MongoClient, errors
db = MongoClient(config.db_url) db = MongoClient(config.db_url)
try: try:
db.server_info() db.server_info()
except errors.ConnectionFailure as e: except errors.ConnectionFailure as e:
raise RuntimeError( raise RuntimeError(
"MongoDB server isn't available! " "MongoDB server isn't available! "
f"Provided url:  { f"Provided url: {config.db_url}. "
config.db_url "Enter valid URL and restart installation"
}. " ) from e
"Enter valid URL and restart installation"
) from e
install_type = sys.argv[1] if len(sys.argv) > 1 else "3" install_type = sys.argv[1] if len(sys.argv) > 1 else "3"
if install_type == "1": if install_type == "1":
restart = "pm2 restart Moon" restart = "pm2 restart Moon"
elif install_type == "2": elif install_type == "2":
restart = "sudo systemctl restart Moon" restart = "sudo systemctl restart Moon"
else : else:
restart = "cd Moon-Userbot/ && python main.py" restart = "cd Moon-Userbot/ && python main.py"
app.start() app.start()
try: try:
app.send_message( app.send_message(
"me", "me",
f"<b>[ { f"<b>[{datetime.datetime.now()}] Moon-Userbot launched! \n"
datetime.datetime.now()}] Moon-Userbot launched! \n" "Channel: @moonuserbot\n"
"Channel: @moonuserbot\n" "Custom modules: @moonub_modules\n"
"Custom modules: @moonub_modules\n" "Chat [RU]: @moonub_chat\n"
"Chat [RU]: @moonub_chat\n" f"For restart, enter:</b>\n"
f"For restart, enter:</b>\n" f"<code>{restart}</code>",
f"<code> { )
restart except Exception:
}</code>", pass
) app.stop()
except Exception:
pass
app.stop()

View File

@@ -1,159 +1,164 @@
#!/bin/bash #!/bin/bash
if command -v termux-setup-storage; then 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 echo For termux, please use https://raw.githubusercontent.com/The-MoonTg-project/Moon-Userbot/main/termux-install.sh
exit 1 exit 1
fi fi
if [[$UID != 0]]; then if [[ $UID != 0 ]]; then
echo Please run this script as root echo Please run this script as root
exit 1 exit 1
fi fi
apt update -y apt update -y
apt install python3 python3-pip git ffmpeg wget gnupg -y || exit 2 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 pip" $SUDO_USER
su -c "python3 -m pip install -U wheel pillow" $SUDO_USER su -c "python3 -m pip install -U wheel pillow" $SUDO_USER
if [[-d "Moon-Userbot"]]; then if [[ -d "Moon-Userbot" ]]; then
cd Moon-Userbot cd Moon-Userbot
elif [[-f ".env.dist"]] && [[-f "main.py"]] && [[-d "modules"]]; then elif [[ -f ".env.dist" ]] && [[ -f "main.py" ]] && [[ -d "modules" ]]; then
: :
else else
git clone https://github.com/The-MoonTg-project/Moon-Userbot || exit 2 git clone https://github.com/The-MoonTg-project/Moon-Userbot || exit 2
cd Moon-Userbot || exit 2 cd Moon-Userbot || exit 2
fi fi
if [[-f ".env"]] && [[-f "my_account.session"]]; then if [[ -f ".env" ]] && [[ -f "my_account.session" ]]; then
echo "It seems that Moon-Userbot is already installed. Exiting..." echo "It seems that Moon-Userbot is already installed. Exiting..."
exit exit
fi 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
echo "Enter API_ID and API_HASH" 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)" echo "Leave empty to use defaults (please note that default keys significantly increases your ban chances)"
read -r -p "API_ID > " api_id read -r -p "API_ID > " api_id
if [[$api_id = ""]]; then if [[ $api_id = "" ]]; then
api_id = "2040" api_id="2040"
api_hash = "b18441a1ff607e10a989891a5462e627" api_hash="b18441a1ff607e10a989891a5462e627"
else else
read -r -p "API_HASH > " api_hash read -r -p "API_HASH > " api_hash
fi fi
echo echo
echo "Choose database type:" echo "Choose database type:"
echo "[1] MongoDB db_url" echo "[1] MongoDB db_url"
echo "[2] MongoDB localhost" echo "[2] MongoDB localhost"
echo "[3] Sqlite (default)" echo "[3] Sqlite (default)"
read -r -p "> " db_type read -r -p "> " db_type
echo echo
case $db_type in case $db_type in
1) 1)
echo "Please enter db_url" echo "Please enter db_url"
echo "You can get it here -> " echo "You can get it here -> https://mongodb.com/atlas"
read -r -p "> " db_url read -r -p "> " db_url
db_name = Moon_Userbot db_name=Moon_Userbot
db_type = mongodb db_type=mongodb
;; ;;
2) 2)
if systemctl status mongodb; then if systemctl status mongodb; then
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add - wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add -
source /etc/os-release source /etc/os-release
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $ { 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
UBUNTU_CODENAME apt update
}/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list apt install mongodb -y
apt update systemctl daemon-reload
apt install mongodb -y systemctl enable mongodb
systemctl daemon-reload fi
systemctl enable mongodb systemctl start mongodb
fi
systemctl start mongodb
db_url = mongodb://localhost:27017 db_url=mongodb://localhost:27017
db_name = Moon_Userbot db_name=Moon_Userbot
db_type = mongodb db_type=mongodb
;; ;;
*) *)
db_name = db.sqlite3 db_name=db.sqlite3
db_type = sqlite3 db_type=sqlite3
;; ;;
esac esac
cat > .env << EOL cat > .env << EOL
API_ID=${api_id} API_ID=${api_id}
API_HASH=${api_hash} API_HASH=${api_hash}
# sqlite/sqlite3 or mongo/mongodb # sqlite/sqlite3 or mongo/mongodb
DATABASE_TYPE=${db_type} DATABASE_TYPE=${db_type}
# file name for sqlite3, database name for mongodb # file name for sqlite3, database name for mongodb
DATABASE_NAME=${db_name} DATABASE_NAME=${db_name}
# only for mongodb # only for mongodb
DATABASE_URL=${db_url} DATABASE_URL=${db_url}
EOL EOL
chown -R $SUDO_USER:$SUDO_USER .
echo chown -R $SUDO_USER:$SUDO_USER .
echo "Choose installation type:"
echo "[1] PM2" echo
echo "[2] Systemd service" echo "Choose installation type:"
echo "[3] Custom (default)" echo "[1] PM2"
read -r -p "> " install_type echo "[2] Systemd service"
su -c "python3 install.py ${install_type}" $SUDO_USER || exit 3 echo "[3] Custom (default)"
case $install_type in read -r -p "> " install_type
  1)
    if ! command -v pm2; then su -c "python3 install.py ${install_type}" $SUDO_USER || exit 3
      curl -fsSL https://deb.nodesource.com/setup_17.x | bash
      apt install nodejs -y case $install_type in
      npm install pm2 -g 1)
      su -c "pm2 startup" $SUDO_USER if ! command -v pm2; then
      env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $SUDO_USER --hp /home/$SUDO_USER curl -fsSL https://deb.nodesource.com/setup_17.x | bash
    fi apt install nodejs -y
    su -c "pm2 start main.py --name Moon --interpreter python3" $SUDO_USER npm install pm2 -g
    su -c "pm2 save" $SUDO_USER su -c "pm2 startup" $SUDO_USER
    echo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $SUDO_USER --hp /home/$SUDO_USER
    echo "============================" fi
    echo "Great! Moon-Userbot installed successfully and running now!" su -c "pm2 start main.py --name Moon --interpreter python3" $SUDO_USER
    echo "Installation type: PM2" su -c "pm2 save" $SUDO_USER
    echo "Start with: \"pm2 start Moon\""
    echo "Stop with: \"pm2 stop Moon\"" echo
    echo "Process name: Moon" echo "============================"
    echo "============================" echo "Great! Moon-Userbot installed successfully and running now!"
    ;; echo "Installation type: PM2"
  2) echo "Start with: \"pm2 start Moon\""
    cat > /etc/systemd/system/Moon.service << EOL echo "Stop with: \"pm2 stop Moon\""
[Unit] echo "Process name: Moon"
Description=Service for Moon Userbot echo "============================"
[Service] ;;
Type=simple 2)
ExecStart=$(which python3) ${PWD}/main.py cat > /etc/systemd/system/Moon.service << EOL
WorkingDirectory=${PWD} [Unit]
Restart=always Description=Service for Moon Userbot
User=${SUDO_USER} [Service]
Group=${SUDO_USER} Type=simple
[Install] ExecStart=$(which python3) ${PWD}/main.py
WantedBy=multi-user.target WorkingDirectory=${PWD}
EOL Restart=always
    systemctl daemon-reload User=${SUDO_USER}
    systemctl start Moon Group=${SUDO_USER}
    systemctl enable Moon [Install]
    echo WantedBy=multi-user.target
    echo "============================" EOL
    echo "Great! Moon-Userbot installed successfully and running now!" systemctl daemon-reload
    echo "Installation type: Systemd service" systemctl start Moon
    echo "Start with: \"sudo systemctl start Moon\"" systemctl enable Moon
    echo "Stop with: \"sudo systemctl stop Moon\""
    echo "============================" echo
    ;; echo "============================"
  *) echo "Great! Moon-Userbot installed successfully and running now!"
    echo echo "Installation type: Systemd service"
    echo "============================" echo "Start with: \"sudo systemctl start Moon\""
    echo "Great! Moon-Userbot installed successfully!" echo "Stop with: \"sudo systemctl stop Moon\""
    echo "Installation type: Custom" echo "============================"
    echo "Start with: \"python3 main.py\"" ;;
    echo "============================" *)
    ;; echo
esac echo "============================"
chown -R $SUDO_USER:$SUDO_USER . echo "Great! Moon-Userbot installed successfully!"
echo "Installation type: Custom"
echo "Start with: \"python3 main.py\""
echo "============================"
;;
esac
chown -R $SUDO_USER:$SUDO_USER .

273
main.py
View File

@@ -1,18 +1,18 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import sqlite3 import sqlite3
import subprocess import subprocess
@@ -25,162 +25,135 @@ from importlib import import_module
import logging import logging
import platform import platform
logging.basicConfig(level = logging.INFO) logging.basicConfig(level=logging.INFO)
DeleteAccount.__new__ = None DeleteAccount.__new__ = None
if __name__ == "__main__": if __name__ == "__main__":
script_path = os.path.dirname(os.path.realpath(__file__)) script_path = os.path.dirname(os.path.realpath(__file__))
if script_path != os.getcwd(): if script_path != os.getcwd():
os.chdir(script_path) os.chdir(script_path)
if os.path.exists("./config.ini.old") and not os.path.exists("./.env"): if os.path.exists("./config.ini.old") and not os.path.exists("./.env"):
logging.warning("Old config.ini file detected! Converting to .env...") logging.warning("Old config.ini file detected! Converting to .env...")
import configparser import configparser
parser = configparser.ConfigParser() parser = configparser.ConfigParser()
parser.read("./config.ini.old") parser.read("./config.ini.old")
db_url = parser.get("pyrogram", "db_url") db_url = parser.get("pyrogram", "db_url")
db_name = parser.get("db", "db_name") db_name = parser.get("db", "db_name")
with open(".env.dist") as f: with open(".env.dist") as f:
env_text = f.read().format( env_text = f.read().format(
db_url = db_url, db_url=db_url,
db_name = db_name, db_name=db_name,
db_type = "mongodb", db_type="mongodb",
) )
with open(".env", "w") as f: with open(".env", "w") as f:
f.write(env_text) 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.db import db
from utils.misc import gitrepo, userbot_version from utils.misc import gitrepo, userbot_version
from utils.scripts import restart from utils.scripts import restart
from utils import config from utils import config
app = Client( app = Client(
"my_account", "my_account",
api_id = config.api_id, api_id=config.api_id,
api_hash = config.api_hash, api_hash=config.api_hash,
hide_password = True, hide_password=True,
workdir = script_path, workdir=script_path,
app_version = userbot_version, app_version=userbot_version,
device_model = f"Moon-Userbot @  { device_model=f"Moon-Userbot @ {gitrepo.head.commit.hexsha[:7]}",
gitrepo.head.commit.hexsha[:7]}", system_version=platform.version() + " " + platform.machine(),
system_version = platform.version() + " " + platform.machine(), sleep_threshold=30,
sleep_threshold = 30, test_mode=config.test_server,
test_mode = config.test_server, parse_mode="html",
parse_mode = "html", )
)
try: try:
app.start() app.start()
except sqlite3.OperationalError as e: except sqlite3.OperationalError as e:
if str(e) == "database is locked" and os.name == "posix": if str(e) == "database is locked" and os.name == "posix":
logging.warning( logging.warning(
"Session file is locked. Trying to kill blocking process..." "Session file is locked. Trying to kill blocking process..."
) )
subprocess.run(["fuser", "-k", "my_account.session"]) subprocess.run(["fuser", "-k", "my_account.session"])
restart() restart()
raise raise
except (errors.NotAcceptable, errors.Unauthorized) as e: except (errors.NotAcceptable, errors.Unauthorized) as e:
logging.error( logging.error(
f" { f"{e.__class__.__name__}: {e}\n"
e.__class__.__name__ f"Moving session file to my_account.session-old..."
}:  { )
e os.rename("./my_account.session", "./my_account.session-old")
}\n" restart()
f"Moving session file to my_account.session-old..."
)
os.rename("./my_account.session", "./my_account.session-old")
restart()
success_handlers = 0 success_handlers = 0
failed_handlers = 0 failed_handlers = 0
success_modules = 0 success_modules = 0
failed_modules = 0 failed_modules = 0
for path in sorted((Path("modules")).rglob("*.py")): for path in sorted((Path("modules")).rglob("*.py")):
module_path = ".".join(path.parent.parts + (path.stem,)) module_path = ".".join(path.parent.parts + (path.stem,))
try: try:
module = import_module(module_path) module = import_module(module_path)
for name, obj in vars(module).items(): for name, obj in vars(module).items():
# defaulting to [] if obj isn't a function-handler # defaulting to [] if obj isn't a function-handler
for handler, group in getattr(obj, "handlers", []): for handler, group in getattr(obj, "handlers", []):
try: try:
app.add_handler(handler, group) app.add_handler(handler, group)
success_handlers += 1 success_handlers += 1
except Exception as e: except Exception as e:
failed_handlers += 1 failed_handlers += 1
logging.warning( logging.warning(
f"Can't add  { f"Can't add {module_path}.{name}.{handler.__name__}: {e.__class__.__name__}: {e}"
module_path )
}. { except Exception as e:
name logging.warning(
}. { f"Can't import module {module_path}: {e.__class__.__name__}: {e}"
handler.__name__ )
}:  { failed_modules += 1
e.__class__.__name__ else:
}:  { success_modules += 1
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( logging.info(
f"Imported  { f"Imported {success_handlers} handlers from {success_modules} modules."
success_handlers )
} handlers from  { if failed_modules:
success_modules logging.warning(f"Failed to import {failed_modules} modules")
} modules." if failed_handlers:
) logging.warning(f"Failed to add {failed_handlers} to handlers")
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: if len(sys.argv) == 4:
restart_type = sys.argv[3] restart_type = sys.argv[3]
if restart_type == "1": if restart_type == "1":
text = "<b>Update process completed!</b>" text = "<b>Update process completed!</b>"
else : else:
text = "<b>Restart completed!</b>" text = "<b>Restart completed!</b>"
try: try:
app.send_message( app.send_message(
chat_id = sys.argv[1], text = text, reply_to_message_id = int(sys.argv[2]) 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) except errors.RPCError:
app.send_message(chat_id=sys.argv[1], text=text)
# required for sessionkiller module # required for sessionkiller module
if db.get("core.sessionkiller", "enabled", False): if db.get("core.sessionkiller", "enabled", False):
db.set( db.set(
"core.sessionkiller", "core.sessionkiller",
"auths_hashes", "auths_hashes",
[auth.hash for auth in app.send(GetAuthorizations()).authorizations], [auth.hash for auth in app.send(
) GetAuthorizations()).authorizations],
)
logging.info("Moon-Userbot started!") logging.info("Moon-Userbot started!")
idle() idle()

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +1,129 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import json import json
from html import escape as t from html import escape as t
from time import perf_counter from time import perf_counter
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.errors.exceptions.flood_420 import FloodWait from pyrogram.errors.exceptions.flood_420 import FloodWait
from pyrogram.raw.functions.messages.get_all_chats import GetAllChats from pyrogram.raw.functions.messages.get_all_chats import GetAllChats
from pyrogram.types import Message from pyrogram.types import Message
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
from utils.scripts import format_exc from utils.scripts import format_exc
@Client.on_message(filters.command("admcount", prefix) & filters.me) @Client.on_message(filters.command("admcount", prefix) & filters.me)
async def admcount(client: Client, message: Message): async def admcount(client: Client, message: Message):
    await message.edit("<b>Retrieving information... (it'll take some time)</b>") await message.edit("<b>Retrieving information... (it'll take some time)</b>")
    start = perf_counter() start = perf_counter()
    try: try:
        response = await client.send(GetAllChats(except_ids=[])) response = await client.send(GetAllChats(except_ids=[]))
        chats = response["chats"] chats = response["chats"]
        adminned_chats = 0 adminned_chats = 0
        owned_chats = 0 owned_chats = 0
        owned_usernamed_chats = 0 owned_usernamed_chats = 0
        for chat in chats: for chat in chats:
            if getattr(chat, "migrated_to", None): if getattr(chat, "migrated_to", None):
                continue continue
            if chat.creator and getattr(chat, "username", None): if chat.creator and getattr(chat, "username", None):
                owned_usernamed_chats += 1 owned_usernamed_chats += 1
            elif chat.creator: elif chat.creator:
                owned_chats += 1 owned_chats += 1
            elif getattr(chat, "admin_rights", None): elif getattr(chat, "admin_rights", None):
                adminned_chats += 1 adminned_chats += 1
    except Exception as e: except Exception as e:
        await message.edit(format_exc(e)) await message.edit(format_exc(e))
        return return
    stop = perf_counter() stop = perf_counter()
    await message.edit( await message.edit(
        f"<b><u>Total:</u></b> {adminned_chats + owned_chats + owned_usernamed_chats}" f"<b><u>Total:</u></b> {adminned_chats + owned_chats + owned_usernamed_chats}"
        f"\n<b><u>Adminned chats:</u></b> {adminned_chats}\n" f"\n<b><u>Adminned chats:</u></b> {adminned_chats}\n"
        f"<b><u>Owned chats:</u></b> {owned_chats}\n" f"<b><u>Owned chats:</u></b> {owned_chats}\n"
        f"<b><u>Owned chats with username:</u></b> {owned_usernamed_chats}\n\n" f"<b><u>Owned chats with username:</u></b> {owned_usernamed_chats}\n\n"
        f"Done at {round(stop - start, 3)} seconds.\n\n" f"Done at {round(stop - start, 3)} seconds.\n\n"
        f"<b>Get full list: </b><code>{prefix}admlist</code>" f"<b>Get full list: </b><code>{prefix}admlist</code>"
    ) )
@Client.on_message(filters.command("admlist", prefix) & filters.me) @Client.on_message(filters.command("admlist", prefix) & filters.me)
async def admlist(client: Client, message: Message): async def admlist(client: Client, message: Message):
    await message.edit("<b>Retrieving information... (it'll take some time)</b>") await message.edit("<b>Retrieving information... (it'll take some time)</b>")
    start = perf_counter() start = perf_counter()
    try: try:
        response = await client.send(GetAllChats(except_ids=[])) response = await client.send(GetAllChats(except_ids=[]))
        chats = response["chats"] chats = response["chats"]
        adminned_chats = [] adminned_chats = []
        owned_chats = [] owned_chats = []
        owned_usernamed_chats = [] owned_usernamed_chats = []
        for chat in chats: for chat in chats:
            if getattr(chat, "migrated_to", None) is not None: if getattr(chat, "migrated_to", None) is not None:
                continue continue
            if chat.creator and getattr(chat, "username", None): if chat.creator and getattr(chat, "username", None):
                owned_usernamed_chats.append(chat) owned_usernamed_chats.append(chat)
            elif chat.creator: elif chat.creator:
                owned_chats.append(chat) owned_chats.append(chat)
            elif getattr(chat, "admin_rights", None): elif getattr(chat, "admin_rights", None):
                adminned_chats.append(chat) adminned_chats.append(chat)
        text = "<b>Adminned chats:</b>\n" text = "<b>Adminned chats:</b>\n"
        for index, chat in enumerate(adminned_chats): for index, chat in enumerate(adminned_chats):
            text += ( text += (
                f"{index + 1}. <a href=https://t.me/c/{chat.id}/1>{chat.title}</a>\n" f"{index + 1}. <a href=https://t.me/c/{chat.id}/1>{chat.title}</a>\n"
            ) )
        text += "\n<b>Owned chats:</b>\n" text += "\n<b>Owned chats:</b>\n"
        for index, chat in enumerate(owned_chats): for index, chat in enumerate(owned_chats):
            text += ( text += (
                f"{index + 1}. <a href=https://t.me/c/{chat.id}/1>{chat.title}</a>\n" f"{index + 1}. <a href=https://t.me/c/{chat.id}/1>{chat.title}</a>\n"
            ) )
        text += "\n<b>Owned chats with username:</b>\n" text += "\n<b>Owned chats with username:</b>\n"
        for index, chat in enumerate(owned_usernamed_chats): for index, chat in enumerate(owned_usernamed_chats):
            text += ( text += (
                f"{index + 1}. <a href=https://t.me/{chat.username}>{chat.title}</a>\n" f"{index + 1}. <a href=https://t.me/{chat.username}>{chat.title}</a>\n"
            ) )
        stop = perf_counter() stop = perf_counter()
        total_count = ( total_count = (
            len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats) len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats)
        ) )
        await message.edit( await message.edit(
            text + "\n" text + "\n"
            f"<b><u>Total:</u></b> {total_count}" f"<b><u>Total:</u></b> {total_count}"
            f"\n<b><u>Adminned chats:</u></b> {len(adminned_chats)}\n" f"\n<b><u>Adminned chats:</u></b> {len(adminned_chats)}\n"
            f"<b><u>Owned chats:</u></b> {len(owned_chats)}\n" f"<b><u>Owned chats:</u></b> {len(owned_chats)}\n"
            f"<b><u>Owned chats with username:</u></b> {len(owned_usernamed_chats)}\n\n" f"<b><u>Owned chats with username:</u></b> {len(owned_usernamed_chats)}\n\n"
            f"Done at {round(stop - start, 3)} seconds." f"Done at {round(stop - start, 3)} seconds."
        ) )
    except Exception as e: except Exception as e:
        await message.edit(format_exc(e)) await message.edit(format_exc(e))
        return return
modules_help["admlist"] = { modules_help["admlist"] = {
    "admcount": "Get count of adminned and owned chats", "admcount": "Get count of adminned and owned chats",
    "admlist": "Get list of adminned and owned chats", "admlist": "Get list of adminned and owned chats",
} }

View File

@@ -1,85 +1,86 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import datetime import datetime
from pyrogram import Client, filters, types from pyrogram import Client, filters, types
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
from utils.db import db from utils.db import db
# avoid using global variables # avoid using global variables
afk_info = db.get( afk_info = db.get(
    "core.afk", "core.afk",
    "afk_info", "afk_info",
    { {
        "start": 0, "start": 0,
        "is_afk": False, "is_afk": False,
        "reason": "", "reason": "",
    }, },
) )
is_afk = filters.create(lambda _, __, ___: afk_info["is_afk"]) is_afk = filters.create(lambda _, __, ___: afk_info["is_afk"])
@Client.on_message( @Client.on_message(
    is_afk is_afk
    & (filters.private | filters.mentioned) & (filters.private | filters.mentioned)
    & ~filters.channel & ~filters.channel
    & ~filters.me & ~filters.me
    & ~filters.bot & ~filters.bot
) )
async def afk_handler(_, message: types.Message): async def afk_handler(_, message: types.Message):
    start = datetime.datetime.fromtimestamp(afk_info["start"]) start = datetime.datetime.fromtimestamp(afk_info["start"])
    end = datetime.datetime.now().replace(microsecond=0) end = datetime.datetime.now().replace(microsecond=0)
    afk_time = end - start afk_time = end - start
    await message.reply( await message.reply(
        f"<b>I'm AFK {afk_time}\n" f"Reason:</b> <i>{afk_info['reason']}</i>" f"<b>I'm AFK {afk_time}\n" f"Reason:</b> <i>{afk_info['reason']}</i>"
    ) )
@Client.on_message(filters.command("afk", prefix) & filters.me) @Client.on_message(filters.command("afk", prefix) & filters.me)
async def afk(_, message): async def afk(_, message):
    if len(message.text.split()) >= 2: if len(message.text.split()) >= 2:
        reason = message.text.split(" ", maxsplit=1)[1] reason = message.text.split(" ", maxsplit=1)[1]
    else: else:
        reason = "None" reason = "None"
    afk_info["start"] = int(datetime.datetime.now().timestamp()) afk_info["start"] = int(datetime.datetime.now().timestamp())
    afk_info["is_afk"] = True afk_info["is_afk"] = True
    afk_info["reason"] = reason afk_info["reason"] = reason
    await message.edit(f"<b>I'm going AFK.\n" f"Reason:</b> <i>{reason}</i>") await message.edit(f"<b>I'm going AFK.\n" f"Reason:</b> <i>{reason}</i>")
    db.set("core.afk", "afk_info", afk_info) db.set("core.afk", "afk_info", afk_info)
@Client.on_message(filters.command("unafk", prefix) & filters.me) @Client.on_message(filters.command("unafk", prefix) & filters.me)
async def unafk(_, message): async def unafk(_, message):
    if afk_info["is_afk"]: if afk_info["is_afk"]:
        start = datetime.datetime.fromtimestamp(afk_info["start"]) start = datetime.datetime.fromtimestamp(afk_info["start"])
        end = datetime.datetime.now().replace(microsecond=0) end = datetime.datetime.now().replace(microsecond=0)
        afk_time = end - start afk_time = end - start
        await message.edit(f"<b>I'm not AFK anymore.\n" f"I was afk {afk_time}</b>") await message.edit(f"<b>I'm not AFK anymore.\n" f"I was afk {afk_time}</b>")
        afk_info["is_afk"] = False afk_info["is_afk"] = False
    else: else:
        await message.edit("<b>You weren't afk</b>") await message.edit("<b>You weren't afk</b>")
    db.set("core.afk", "afk_info", afk_info) db.set("core.afk", "afk_info", afk_info)
modules_help["afk"] = {"afk [reason]": "Go to afk", "unafk": "Get out of AFK"} 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"}

View File

@@ -1,125 +1,126 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.raw import functions from pyrogram.raw import functions
from pyrogram.types import Message from pyrogram.types import Message
from utils.db import db from utils.db import db
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
anti_pm_enabled = filters.create( anti_pm_enabled = filters.create(
    lambda _, __, ___: db.get("core.antipm", "status", False) lambda _, __, ___: db.get("core.antipm", "status", False)
) )
in_contact_list = filters.create(lambda _, __, message: message.from_user.is_contact) in_contact_list = filters.create(
lambda _, __, message: message.from_user.is_contact)
is_support = filters.create(lambda _, __, message: message.chat.is_support)
is_support = filters.create(lambda _, __, message: message.chat.is_support)
@Client.on_message(
    filters.private @Client.on_message(
    & ~filters.me filters.private
    & ~filters.bot & ~filters.me
    & ~in_contact_list & ~filters.bot
    & ~is_support & ~in_contact_list
    & anti_pm_enabled & ~is_support
) & anti_pm_enabled
async def anti_pm_handler(client: Client, message: Message): )
    user_info = await client.resolve_peer(message.chat.id) async def anti_pm_handler(client: Client, message: Message):
    if db.get("core.antipm", "spamrep", False): user_info = await client.resolve_peer(message.chat.id)
        await client.send(functions.messages.ReportSpam(peer=user_info)) if db.get("core.antipm", "spamrep", False):
    if db.get("core.antipm", "block", False): await client.send(functions.messages.ReportSpam(peer=user_info))
        await client.send(functions.contacts.Block(id=user_info)) if db.get("core.antipm", "block", False):
    await client.send( await client.send(functions.contacts.Block(id=user_info))
        functions.messages.DeleteHistory(peer=user_info, max_id=0, revoke=True) 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): @Client.on_message(filters.command(["antipm", "anti_pm"], prefix) & filters.me)
    if len(message.command) == 1: async def anti_pm(_, message: Message):
        if db.get("core.antipm", "status", False): if len(message.command) == 1:
            await message.edit( if db.get("core.antipm", "status", False):
                "<b>Anti-PM status: enabled\n" await message.edit(
                f"Disable with: </b><code>{prefix}antipm disable</code>" "<b>Anti-PM status: enabled\n"
            ) f"Disable with: </b><code>{prefix}antipm disable</code>"
        else: )
            await message.edit( else:
                "<b>Anti-PM status: disabled\n" await message.edit(
                f"Enable with: </b><code>{prefix}antipm enable</code>" "<b>Anti-PM status: disabled\n"
            ) f"Enable with: </b><code>{prefix}antipm enable</code>"
    elif message.command[1] in ["enable", "on", "1", "yes", "true"]: )
        db.set("core.antipm", "status", True) elif message.command[1] in ["enable", "on", "1", "yes", "true"]:
        await message.edit("<b>Anti-PM enabled!</b>") db.set("core.antipm", "status", True)
    elif message.command[1] in ["disable", "off", "0", "no", "false"]: await message.edit("<b>Anti-PM enabled!</b>")
        db.set("core.antipm", "status", False) elif message.command[1] in ["disable", "off", "0", "no", "false"]:
        await message.edit("<b>Anti-PM disabled!</b>") db.set("core.antipm", "status", False)
    else: await message.edit("<b>Anti-PM disabled!</b>")
        await message.edit(f"<b>Usage: {prefix}antipm [enable|disable]</b>") else:
await message.edit(f"<b>Usage: {prefix}antipm [enable|disable]</b>")
@Client.on_message(filters.command(["antipm_report"], prefix) & filters.me)
async def antipm_report(_, message: Message): @Client.on_message(filters.command(["antipm_report"], prefix) & filters.me)
    if len(message.command) == 1: async def antipm_report(_, message: Message):
        if db.get("core.antipm", "spamrep", False): if len(message.command) == 1:
            await message.edit( if db.get("core.antipm", "spamrep", False):
                "<b>Spam-reporting enabled.\n" await message.edit(
                f"Disable with: </b><code>{prefix}antipm_report disable</code>" "<b>Spam-reporting enabled.\n"
            ) f"Disable with: </b><code>{prefix}antipm_report disable</code>"
        else: )
            await message.edit( else:
                "<b>Spam-reporting disabled.\n" await message.edit(
                f"Enable with: </b><code>{prefix}antipm_report enable</code>" "<b>Spam-reporting disabled.\n"
            ) f"Enable with: </b><code>{prefix}antipm_report enable</code>"
    elif message.command[1] in ["enable", "on", "1", "yes", "true"]: )
        db.set("core.antipm", "spamrep", True) elif message.command[1] in ["enable", "on", "1", "yes", "true"]:
        await message.edit("<b>Spam-reporting enabled!</b>") db.set("core.antipm", "spamrep", True)
    elif message.command[1] in ["disable", "off", "0", "no", "false"]: await message.edit("<b>Spam-reporting enabled!</b>")
        db.set("core.antipm", "spamrep", False) elif message.command[1] in ["disable", "off", "0", "no", "false"]:
        await message.edit("<b>Spam-reporting disabled!</b>") db.set("core.antipm", "spamrep", False)
    else: await message.edit("<b>Spam-reporting disabled!</b>")
        await message.edit(f"<b>Usage: {prefix}antipm_report [enable|disable]</b>") else:
await message.edit(f"<b>Usage: {prefix}antipm_report [enable|disable]</b>")
@Client.on_message(filters.command(["antipm_block"], prefix) & filters.me)
async def antipm_block(_, message: Message): @Client.on_message(filters.command(["antipm_block"], prefix) & filters.me)
    if len(message.command) == 1: async def antipm_block(_, message: Message):
        if db.get("core.antipm", "block", False): if len(message.command) == 1:
            await message.edit( if db.get("core.antipm", "block", False):
                "<b>Blocking users enabled.\n" await message.edit(
                f"Disable with: </b><code>{prefix}antipm_block disable</code>" "<b>Blocking users enabled.\n"
            ) f"Disable with: </b><code>{prefix}antipm_block disable</code>"
        else: )
            await message.edit( else:
                "<b>Blocking users disabled.\n" await message.edit(
                f"Enable with: </b><code>{prefix}antipm_block enable</code>" "<b>Blocking users disabled.\n"
            ) f"Enable with: </b><code>{prefix}antipm_block enable</code>"
    elif message.command[1] in ["enable", "on", "1", "yes", "true"]: )
        db.set("core.antipm", "block", True) elif message.command[1] in ["enable", "on", "1", "yes", "true"]:
        await message.edit("<b>Blocking users enabled!</b>") db.set("core.antipm", "block", True)
    elif message.command[1] in ["disable", "off", "0", "no", "false"]: await message.edit("<b>Blocking users enabled!</b>")
        db.set("core.antipm", "block", False) elif message.command[1] in ["disable", "off", "0", "no", "false"]:
        await message.edit("<b>Blocking users disabled!</b>") db.set("core.antipm", "block", False)
    else: await message.edit("<b>Blocking users disabled!</b>")
        await message.edit(f"<b>Usage: {prefix}antipm_block [enable|disable]</b>") else:
await message.edit(f"<b>Usage: {prefix}antipm_block [enable|disable]</b>")
modules_help["antipm"] = {
    "antipm [enable|disable]*": "When enabled, deletes all messages from users who are not in the contact book", modules_help["antipm"] = {
    "antipm_report [enable|disable]*": "Enable spam reporting", "antipm [enable|disable]*": "When enabled, deletes all messages from users who are not in the contact book",
    "antipm_block [enable|disable]*": "Enable user blocking", "antipm_report [enable|disable]*": "Enable spam reporting",
} "antipm_block [enable|disable]*": "Enable user blocking",
}

View File

@@ -1,72 +1,88 @@
from pyrogram import Client, filters # Moon-Userbot - telegram userbot
from pyrogram.errors import FloodWait # Copyright (C) 2020-present Moon Userbot Organization
from pyrogram.raw import functions, types #
from pyrogram.types import Message # 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
from utils.misc import modules_help, prefix # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
@Client.on_message(filters.command(["clear_@"], prefix) & filters.me) # This program is distributed in the hope that it will be useful,
async def solo_mention_clear(client: Client, message: Message): # but WITHOUT ANY WARRANTY; without even the implied warranty of
    await message.delete() # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    peer = await client.resolve_peer(message.chat.id) # GNU General Public License for more details.
    request = functions.messages.ReadMentions(peer=peer)
    await client.send(request) # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
@Client.on_message(filters.command(["clear_all_@"], prefix) & filters.me) from pyrogram import Client, filters
async def global_mention_clear(client: Client, message: Message): from pyrogram.errors import FloodWait
    request = functions.messages.GetAllChats(except_ids=[]) from pyrogram.raw import functions, types
    try: from pyrogram.types import Message
        result = await client.send(request)
    except FloodWait as e: from utils.misc import modules_help, prefix
        await message.edit_text(
            f"<code>FloodWait received. Wait {e.x} seconds before trying again</code>"
        ) @Client.on_message(filters.command(["clear_@"], prefix) & filters.me)
        return async def solo_mention_clear(client: Client, message: Message):
    await message.delete() await message.delete()
    for chat in result.chats: peer = await client.resolve_peer(message.chat.id)
        if type(chat) is types.Chat: request = functions.messages.ReadMentions(peer=peer)
            peer_id = -chat.id await client.send(request)
        elif type(chat) is types.Channel:
            peer_id = int(f"-100{chat.id}")
        peer = await client.resolve_peer(peer_id) @Client.on_message(filters.command(["clear_all_@"], prefix) & filters.me)
        request = functions.messages.ReadMentions(peer=peer) async def global_mention_clear(client: Client, message: Message):
        await client.send(request) request = functions.messages.GetAllChats(except_ids=[])
try:
result = await client.send(request)
@Client.on_message(filters.command(["clear_reacts"], prefix) & filters.me) except FloodWait as e:
async def solo_reaction_clear(client: Client, message: Message): await message.edit_text(
    await message.delete() f"<code>FloodWait received. Wait {e.x} seconds before trying again</code>"
    peer = await client.resolve_peer(message.chat.id) )
    request = functions.messages.ReadReactions(peer=peer) return
    await client.send(request) await message.delete()
for chat in result.chats:
if type(chat) is types.Chat:
@Client.on_message(filters.command(["clear_all_reacts"], prefix) & filters.me) peer_id = -chat.id
async def global_reaction_clear(client: Client, message: Message): elif type(chat) is types.Channel:
    request = functions.messages.GetAllChats(except_ids=[]) peer_id = int(f"-100{chat.id}")
    try: peer = await client.resolve_peer(peer_id)
        result = await client.send(request) request = functions.messages.ReadMentions(peer=peer)
    except FloodWait as e: await client.send(request)
        await message.edit_text(
            f"<code>FloodWait received. Wait {e.x} seconds before trying again</code>"
        ) @Client.on_message(filters.command(["clear_reacts"], prefix) & filters.me)
        return async def solo_reaction_clear(client: Client, message: Message):
    await message.delete() await message.delete()
    for chat in result.chats: peer = await client.resolve_peer(message.chat.id)
        if type(chat) is types.Chat: request = functions.messages.ReadReactions(peer=peer)
            peer_id = -chat.id await client.send(request)
        elif type(chat) is types.Channel:
            peer_id = int(f"-100{chat.id}")
        peer = await client.resolve_peer(peer_id) @Client.on_message(filters.command(["clear_all_reacts"], prefix) & filters.me)
        request = functions.messages.ReadReactions(peer=peer) async def global_reaction_clear(client: Client, message: Message):
        await client.send(request) request = functions.messages.GetAllChats(except_ids=[])
try:
result = await client.send(request)
modules_help["clear_notifs"] = { except FloodWait as e:
    "clear_@": "clear all mentions in this chat", await message.edit_text(
    "clear_all_@": "clear all mentions in all chats", f"<code>FloodWait received. Wait {e.x} seconds before trying again</code>"
    "clear_reacts": "clear all reactions in this chat", )
    "clear_all_reacts": "clear all reactions in all chats (except private chats)", 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)",
}

View File

@@ -1,53 +1,53 @@
#  Moon-Userbot - telegram userbot #  Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization #  Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify #  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 #  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or #  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. #  (at your option) any later version.
#  This program is distributed in the hope that it will be useful, #  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of #  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details. #  GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License #  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.types import Message from pyrogram.types import Message
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
# if your module has packages from PyPi # if your module has packages from PyPi
# from utils.scripts import import_library # from utils.scripts import import_library
# example_1 = import_library("example_1") # example_1 = import_library("example_1")
# example_2 = import_library("example_2") # example_2 = import_library("example_2")
# import_library() will automatically install required library # import_library() will automatically install required library
# if it isn't installed # if it isn't installed
@Client.on_message(filters.command("example_edit", prefix) & filters.me) @Client.on_message(filters.command("example_edit", prefix) & filters.me)
async def example_edit(client: Client, message: Message): async def example_edit(client: Client, message: Message):
    await message.edit("<code>This is an example module</code>") await message.edit("<code>This is an example module</code>")
@Client.on_message(filters.command("example_send", prefix) & filters.me) @Client.on_message(filters.command("example_send", prefix) & filters.me)
async def example_send(client: Client, message: Message): async def example_send(client: Client, message: Message):
    await client.send_message(message.chat.id, "<b>This is an example module</b>") await client.send_message(message.chat.id, "<b>This is an example module</b>")
# This adds instructions for your module # This adds instructions for your module
modules_help["example"] = { modules_help["example"] = {
    "example_send": "example send", "example_send": "example send",
    "example_edit": "example edit", "example_edit": "example edit",
} }
# modules_help["example"] = { "example_send [text]": "example send" } # modules_help["example"] = { "example_send [text]": "example send" }
#                  |            |              |        | # | | | |
#                  |            |              |        └─ command description # | | | └─ command description
#           module_name         command_name   └─ optional command arguments # module_name command_name └─ optional command arguments
#        (only snake_case)   (only snake_case too) # (only snake_case) (only snake_case too)

View File

@@ -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 <https://www.gnu.org/licenses/>.
from pyrogram import Client, filters, ContinuePropagation, errors from pyrogram import Client, filters, ContinuePropagation, errors
from pyrogram.types import ( from pyrogram.types import (
Message, Message,
@@ -7,282 +23,256 @@ from pyrogram.types import (
InputMediaAudio, InputMediaAudio,
) )
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
from utils.scripts import format_exc from utils.scripts import format_exc
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from utils.db import db from utils.db import db
def get_filters_chat(chat_id): def get_filters_chat(chat_id):
return db.get("core.filters", f" { return db.get("core.filters", f"{chat_id}", {})
chat_id
}", {})
def set_filters_chat(chat_id, filters_): def set_filters_chat(chat_id, filters_):
return db.set("core.filters", f" { return db.set("core.filters", f"{chat_id}", filters_)
chat_id
}", filters_)
async def contains_filter(_, __, m): 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) contains = filters.create(contains_filter)
# noinspection PyTypeChecker # noinspection PyTypeChecker
@Client.on_message(contains) @Client.on_message(contains)
async def filters_main_handler(client: Client, message: Message): async def filters_main_handler(client: Client, message: Message):
value = get_filters_chat(message.chat.id)[message.text.lower()] value = get_filters_chat(message.chat.id)[message.text.lower()]
try: try:
await client.get_messages(int(value["CHAT_ID"]), int(value["MESSAGE_ID"])) await client.get_messages(int(value["CHAT_ID"]), int(value["MESSAGE_ID"]))
except errors.RPCError: except errors.RPCError:
raise ContinuePropagation raise ContinuePropagation
if value.get("MEDIA_GROUP"): if value.get("MEDIA_GROUP"):
messages_grouped = await client.get_media_group( messages_grouped = await client.get_media_group(
int(value["CHAT_ID"]), int(value["MESSAGE_ID"]) int(value["CHAT_ID"]), int(value["MESSAGE_ID"])
) )
media_grouped_list = [] media_grouped_list = []
for _ in messages_grouped: for _ in messages_grouped:
if _.photo: if _.photo:
if _.caption: if _.caption:
media_grouped_list.append( media_grouped_list.append(
InputMediaPhoto(_.photo.file_id, _.caption.markdown) InputMediaPhoto(_.photo.file_id, _.caption.markdown)
) )
else : else:
media_grouped_list.append(InputMediaPhoto(_.photo.file_id)) media_grouped_list.append(InputMediaPhoto(_.photo.file_id))
elif _.video: elif _.video:
if _.caption: if _.caption:
if _.video.thumbs: if _.video.thumbs:
media_grouped_list.append( media_grouped_list.append(
InputMediaVideo( InputMediaVideo(
_.video.file_id, _.video.file_id,
_.video.thumbs[0].file_id, _.video.thumbs[0].file_id,
_.caption.markdown, _.caption.markdown,
) )
) )
else : else:
media_grouped_list.append( media_grouped_list.append(
InputMediaVideo(_.video.file_id, _.caption.markdown) InputMediaVideo(_.video.file_id,
) _.caption.markdown)
elif _.video.thumbs: )
media_grouped_list.append( elif _.video.thumbs:
InputMediaVideo(_.video.file_id, _.video.thumbs[0].file_id) media_grouped_list.append(
) InputMediaVideo(_.video.file_id,
else : _.video.thumbs[0].file_id)
media_grouped_list.append(InputMediaVideo(_.video.file_id)) )
elif _.audio: else:
if _.caption: media_grouped_list.append(InputMediaVideo(_.video.file_id))
media_grouped_list.append( elif _.audio:
InputMediaAudio(_.audio.file_id, _.caption.markdown) if _.caption:
) media_grouped_list.append(
else : InputMediaAudio(_.audio.file_id, _.caption.markdown)
media_grouped_list.append(InputMediaAudio(_.audio.file_id)) )
elif _.document: else:
if _.caption: media_grouped_list.append(InputMediaAudio(_.audio.file_id))
if _.document.thumbs: elif _.document:
media_grouped_list.append( if _.caption:
InputMediaDocument( if _.document.thumbs:
_.document.file_id, media_grouped_list.append(
_.document.thumbs[0].file_id, InputMediaDocument(
_.caption.markdown, _.document.file_id,
) _.document.thumbs[0].file_id,
) _.caption.markdown,
else : )
media_grouped_list.append( )
InputMediaDocument(_.document.file_id, _.caption.markdown) else:
) media_grouped_list.append(
elif _.document.thumbs: InputMediaDocument(
media_grouped_list.append( _.document.file_id, _.caption.markdown)
InputMediaDocument( )
_.document.file_id, _.document.thumbs[0].file_id elif _.document.thumbs:
) media_grouped_list.append(
) InputMediaDocument(
else : _.document.file_id, _.document.thumbs[0].file_id
media_grouped_list.append(InputMediaDocument(_.document.file_id)) )
await client.send_media_group( )
message.chat.id, else:
media_grouped_list, media_grouped_list.append(
reply_to_message_id = message.message_id, InputMediaDocument(_.document.file_id))
) await client.send_media_group(
else : message.chat.id,
await client.copy_message( media_grouped_list,
message.chat.id, reply_to_message_id=message.message_id,
int(value["CHAT_ID"]), )
int(value["MESSAGE_ID"]), else:
reply_to_message_id = message.message_id, await client.copy_message(
) message.chat.id,
raise ContinuePropagation 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) @Client.on_message(filters.command(["filter"], prefix) & filters.me)
async def filter_handler(client: Client, message: Message): async def filter_handler(client: Client, message: Message):
try: try:
if len(message.text.split()) < 2: if len(message.text.split()) < 2:
return await message.edit( return await message.edit(
f"<b>Usage</b>: <code> { f"<b>Usage</b>: <code>{prefix}filter [name] (Reply required)</code>"
prefix )
}filter [name] (Reply required)</code>" name = message.text.split(maxsplit=1)[1].lower()
) chat_filters = get_filters_chat(message.chat.id)
name = message.text.split(maxsplit = 1)[1].lower() if name in chat_filters.keys():
chat_filters = get_filters_chat(message.chat.id) return await message.edit(
if name in chat_filters.keys(): f"<b>Filter</b> <code>{name}</code> already exists."
return await message.edit( )
f"<b>Filter</b> <code> { if not message.reply_to_message:
name return await message.edit("<b>Reply to message</b> please.")
}</code> already exists."
)
if not message.reply_to_message:
return await message.edit("<b>Reply to message</b> please.")
try: try:
chat = await client.get_chat(db.get("core.notes", "chat_id", 0)) chat = await client.get_chat(db.get("core.notes", "chat_id", 0))
except (errors.RPCError, ValueError, KeyError): except (errors.RPCError, ValueError, KeyError):
# group is not accessible or isn't created # group is not accessible or isn't created
chat = await client.create_supergroup( chat = await client.create_supergroup(
"Moon_Userbot_Notes_Filters", "Don't touch this group, please" "Moon_Userbot_Notes_Filters", "Don't touch this group, please"
) )
db.set("core.notes", "chat_id", chat.id) db.set("core.notes", "chat_id", chat.id)
chat_id = chat.id chat_id = chat.id
if message.reply_to_message.media_group_id: if message.reply_to_message.media_group_id:
get_media_group = [ get_media_group = [
_.message_id _.message_id
for _ in await client.get_media_group( for _ in await client.get_media_group(
message.chat.id, message.reply_to_message.message_id message.chat.id, message.reply_to_message.message_id
) )
] ]
try: try:
message_id = await client.forward_messages( message_id = await client.forward_messages(
chat_id, message.chat.id, get_media_group chat_id, message.chat.id, get_media_group
) )
except errors.ChatForwardsRestricted: except errors.ChatForwardsRestricted:
await message.edit( await message.edit(
"<b>Forwarding messages is restricted by chat admins</b>" "<b>Forwarding messages is restricted by chat admins</b>"
) )
return return
filter_ = { filter_ = {
"MESSAGE_ID": str(message_id[1].message_id), "MESSAGE_ID": str(message_id[1].message_id),
"MEDIA_GROUP": True, "MEDIA_GROUP": True,
"CHAT_ID": str(chat_id), "CHAT_ID": str(chat_id),
} else : }
try: else:
message_id = await message.reply_to_message.forward(chat_id) try:
except errors.ChatForwardsRestricted: message_id = await message.reply_to_message.forward(chat_id)
if message.reply_to_message.text: except errors.ChatForwardsRestricted:
# manual copy if message.reply_to_message.text:
message_id = await client.send_message( # manual copy
chat_id, message.reply_to_message.text message_id = await client.send_message(
) chat_id, message.reply_to_message.text
else : )
await message.edit( else:
"<b>Forwarding messages is restricted by chat admins</b>" await message.edit(
) "<b>Forwarding messages is restricted by chat admins</b>"
return )
filter_ = { return
"MEDIA_GROUP": False, filter_ = {
"MESSAGE_ID": str(message_id.message_id), "MEDIA_GROUP": False,
"CHAT_ID": str(chat_id), "MESSAGE_ID": str(message_id.message_id),
} "CHAT_ID": str(chat_id),
}
chat_filters.update({ chat_filters.update({name: filter_})
name: filter_
})
set_filters_chat(message.chat.id, chat_filters) set_filters_chat(message.chat.id, chat_filters)
return await message.edit(f"<b>Filter</b> <code> { return await message.edit(f"<b>Filter</b> <code>{name}</code> has been added.")
name except Exception as e:
}</code> has been added.") return await message.edit(format_exc(e))
except Exception as e:
return await message.edit(format_exc(e))
@Client.on_message(filters.command(["filters"], prefix) & filters.me) @Client.on_message(filters.command(["filters"], prefix) & filters.me)
async def filters_handler(client: Client, message: Message): async def filters_handler(client: Client, message: Message):
try: try:
text = "" text = ""
for index, a in enumerate(get_filters_chat(message.chat.id).items(), start = 1): for index, a in enumerate(get_filters_chat(message.chat.id).items(), start=1):
key, item = a key, item = a
key = key.replace("<", "").replace(">", "") key = key.replace("<", "").replace(">", "")
text += f" { text += f"{index}. <code>{key}</code>\n"
index text = f"<b>Your filters in current chat</b>:\n\n" f"{text}"
}. <code> { text = text[:4096]
key return await message.edit(text)
}</code>\n" except Exception as e:
text = f"<b>Your filters in current chat</b>:\n\n" f" { return await message.edit(format_exc(e))
text
}"
text = text[:4096]
return await message.edit(text)
except Exception as e:
return await message.edit(format_exc(e))
@Client.on_message( @Client.on_message(
filters.command(["delfilter", "filterdel", "fdel"], prefix) & filters.me filters.command(["delfilter", "filterdel", "fdel"], prefix) & filters.me
) )
async def filter_del_handler(client: Client, message: Message): async def filter_del_handler(client: Client, message: Message):
try: try:
if len(message.text.split()) < 2: if len(message.text.split()) < 2:
return await message.edit(f"<b>Usage</b>: <code> { return await message.edit(f"<b>Usage</b>: <code>{prefix}fdel [name]</code>")
prefix name = message.text.split(maxsplit=1)[1].lower()
}fdel [name]</code>") chat_filters = get_filters_chat(message.chat.id)
name = message.text.split(maxsplit = 1)[1].lower() if name not in chat_filters.keys():
chat_filters = get_filters_chat(message.chat.id) return await message.edit(
if name not in chat_filters.keys(): f"<b>Filter</b> <code>{name}</code> doesn't exists."
return await message.edit( )
f"<b>Filter</b> <code> { del chat_filters[name]
name set_filters_chat(message.chat.id, chat_filters)
}</code> doesn't exists." return await message.edit(
) f"<b>Filter</b> <code>{name}</code> has been deleted."
del chat_filters[name] )
set_filters_chat(message.chat.id, chat_filters) except Exception as e:
return await message.edit( return await message.edit(format_exc(e))
f"<b>Filter</b> <code> {
name
}</code> has been deleted."
)
except Exception as e:
return await message.edit(format_exc(e))
@Client.on_message(filters.command(["fsearch"], prefix) & filters.me) @Client.on_message(filters.command(["fsearch"], prefix) & filters.me)
async def filter_search_handler(client: Client, message: Message): async def filter_search_handler(client: Client, message: Message):
try: try:
if len(message.text.split()) < 2: if len(message.text.split()) < 2:
return await message.edit( return await message.edit(
f"<b>Usage</b>: <code> { f"<b>Usage</b>: <code>{prefix}fsearch [name]</code>"
prefix )
}fsearch [name]</code>" name = message.text.split(maxsplit=1)[1].lower()
) chat_filters = get_filters_chat(message.chat.id)
name = message.text.split(maxsplit = 1)[1].lower() if name not in chat_filters.keys():
chat_filters = get_filters_chat(message.chat.id) return await message.edit(
if name not in chat_filters.keys(): f"<b>Filter</b> <code>{name}</code> doesn't exists."
return await message.edit( )
f"<b>Filter</b> <code> { return await message.edit(
name f"<b>Trigger</b>:\n<code>{name}</code"
}</code> doesn't exists." f">\n<b>Answer</b>:\n{chat_filters[name]}"
) )
return await message.edit( except Exception as e:
f"<b>Trigger</b>:\n<code> { return await message.edit(format_exc(e))
name
}</code"
f">\n<b>Answer</b>:\n {
chat_filters[name]}"
)
except Exception as e:
return await message.edit(format_exc(e))
modules_help["filters"] = { modules_help["filters"] = {
"filter [name]": "Create filter (Reply required)", "filter [name]": "Create filter (Reply required)",
"filters": "List of all triggers", "filters": "List of all triggers",
"fdel [name]": "Delete filter by name", "fdel [name]": "Delete filter by name",
"fsearch [name]": "Info filter by name", "fsearch [name]": "Info filter by name",
} }

View File

@@ -1,18 +1,18 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.types import Message 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) @Client.on_message(filters.command(["help", "h"], prefix) & filters.me)
async def help_cmd(_, message: Message): async def help_cmd(_, message: Message):
if len(message.command) == 1: if len(message.command) == 1:
msg_edited = False msg_edited = False
text = ( text = (
"<b>Help for <a href=https://t.me/Moonub_chat>Moon-Userbot</a>\n" "<b>Help for <a href=https://t.me/Moonub_chat>Moon-Userbot</a>\n"
f"For more help on how to use a command, type <code> { f"For more help on how to use a command, type <code>{prefix}help [module]</code>\n\n"
prefix "Available Modules:\n"
}help [module]</code>\n\n" )
"Available Modules:\n"
)
for module_name, module_commands in modules_help.items(): for module_name, module_commands in modules_help.items():
text += " {}: {}\n".format( text += " {}: {}\n".format(
module_name.title(), module_name.title(),
" ".join( " ".join(
[ [
f"<code> { f"<code>{prefix + cmd_name.split()[0]}</code>"
prefix + cmd_name.split()[0]}</code>" for cmd_name in module_commands.keys()
for cmd_name in module_commands.keys() ]
] ),
), )
) if len(text) >= 2048:
if len(text) >= 2048: text += "</b>"
text += "</b>" if msg_edited:
if msg_edited: await message.reply(text, disable_web_page_preview=True)
await message.reply(text, disable_web_page_preview = True) else:
else : await message.edit(text, disable_web_page_preview=True)
await message.edit(text, disable_web_page_preview = True) msg_edited = True
msg_edited = True text = "<b>"
text = "<b>"
text += f"\nThe number of modules in the userbot:  { text += f"\nThe number of modules in the userbot: {len(modules_help) / 1}</b>"
len(modules_help) / 1
}</b>"
if msg_edited: if msg_edited:
await message.reply(text, disable_web_page_preview = True) await message.reply(text, disable_web_page_preview=True)
else : else:
await message.edit(text, disable_web_page_preview = True) await message.edit(text, disable_web_page_preview=True)
elif message.command[1].lower() in modules_help: elif message.command[1].lower() in modules_help:
await message.edit(format_module_help(message.command[1].lower())) await message.edit(format_module_help(message.command[1].lower()))
else : else:
# TODO: refactor this cringe # TODO: refactor this cringe
command_name = message.command[1].lower() command_name = message.command[1].lower()
for name, commands in modules_help.items(): for name, commands in modules_help.items():
for command in commands.keys(): for command in commands.keys():
if command.split()[0] == command_name: if command.split()[0] == command_name:
cmd = command.split(maxsplit = 1) cmd = command.split(maxsplit=1)
cmd_desc = commands[command] cmd_desc = commands[command]
return await message.edit( return await message.edit(
f"<b>Help for command <code> { f"<b>Help for command <code>{prefix}{command_name}</code>\n"
prefix f"Module: {name} (<code>{prefix}help {name}</code>)</b>\n\n"
} { f"<code>{prefix}{cmd[0]}</code>"
command_name f"{' <code>' + cmd[1] + '</code>' if len(cmd) > 1 else ''}"
}</code>\n" f" — <i>{cmd_desc}</i>"
f"Module:  { )
name await message.edit(f"<b>Module {command_name} not found</b>")
} (<code> {
prefix
}help  {
name
}</code>)</b>\n\n"
f"<code> {
prefix
} {
cmd[0]}</code>"
f" {
' <code>' + cmd[1] + '</code>' if len(cmd) > 1 else ''
}"
f" — <i> {
cmd_desc
}</i>"
)
await message.edit(f"<b>Module  {
command_name
} not found</b>")
modules_help["help"] = { modules_help["help"] = {
"help [module/command name]": "Get common/module/command help" "help [module/command name]": "Get common/module/command help"}
}

View File

@@ -1,225 +1,225 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import hashlib import hashlib
import os import os
import requests import requests
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.types import Message from pyrogram.types import Message
from utils.scripts import restart from utils.scripts import restart
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
BASE_PATH = os.path.abspath(os.getcwd()) BASE_PATH = os.path.abspath(os.getcwd())
@Client.on_message(filters.command(["modhash", "mh"], prefix) & filters.me) @Client.on_message(filters.command(["modhash", "mh"], prefix) & filters.me)
async def get_mod_hash(_, message: Message): async def get_mod_hash(_, message: Message):
    if len(message.command) == 1: if len(message.command) == 1:
        return return
    url = message.command[1].lower() url = message.command[1].lower()
    resp = requests.get(url) resp = requests.get(url)
    if not resp.ok: if not resp.ok:
        await message.edit( await message.edit(
            f"<b>Troubleshooting with downloading module <code>{url}</code></b>" f"<b>Troubleshooting with downloading module <code>{url}</code></b>"
        ) )
        return return
    await message.edit( await message.edit(
        f"<b>Module hash: <code>{hashlib.sha256(resp.content).hexdigest()}</code>\n" f"<b>Module hash: <code>{hashlib.sha256(resp.content).hexdigest()}</code>\n"
        f"Link: <code>{url}</code>\nFile: <code>{url.split('/')[-1]}</code></b>" f"Link: <code>{url}</code>\nFile: <code>{url.split('/')[-1]}</code></b>"
    ) )
@Client.on_message(filters.command(["loadmod", "lm"], prefix) & filters.me) @Client.on_message(filters.command(["loadmod", "lm"], prefix) & filters.me)
async def loadmod(_, message: Message): async def loadmod(_, message: Message):
    if ( if (
        not ( not (
            message.reply_to_message message.reply_to_message
            and message.reply_to_message.document and message.reply_to_message.document
            and message.reply_to_message.document.file_name.endswith(".py") and message.reply_to_message.document.file_name.endswith(".py")
        ) )
        and len(message.command) == 1 and len(message.command) == 1
    ): ):
        await message.edit("<b>Specify module to download</b>") await message.edit("<b>Specify module to download</b>")
        return return
    if len(message.command) > 1: if len(message.command) > 1:
        url = message.command[1].lower() url = message.command[1].lower()
        if url.startswith( if url.startswith(
            "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/"
        ): ):
            module_name = url.split("/")[-1].split(".")[0] module_name = url.split("/")[-1].split(".")[0]
        elif "/" not in url and "." not in url: elif "/" not in url and "." not in url:
            module_name = url.lower() module_name = url.lower()
            url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py" url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py"
        else: else:
            modules_hashes = requests.get( modules_hashes = requests.get(
                "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt"
            ).text ).text
            resp = requests.get(url) resp = requests.get(url)
            if not resp.ok: if not resp.ok:
                await message.edit( await message.edit(
                    f"<b>Troubleshooting with downloading module <code>{url}</code></b>" f"<b>Troubleshooting with downloading module <code>{url}</code></b>"
                ) )
                return return
            if hashlib.sha256(resp.content).hexdigest() not in modules_hashes: if hashlib.sha256(resp.content).hexdigest() not in modules_hashes:
                return await message.edit( return await message.edit(
                    "<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>" "<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>"
                    "verified</a> modules or from the official " "verified</a> modules or from the official "
                    "<a href=https://github.com/The-MoonTg-project/custom_modules>" "<a href=https://github.com/The-MoonTg-project/custom_modules>"
                    "custom_modules</a> repository are supported!</b>", "custom_modules</a> repository are supported!</b>",
                    disable_web_page_preview=True, disable_web_page_preview=True,
                ) )
            module_name = url.split("/")[-1].split(".")[0] module_name = url.split("/")[-1].split(".")[0]
        resp = requests.get(url) resp = requests.get(url)
        if not resp.ok: if not resp.ok:
            await message.edit(f"<b>Module <code>{module_name}</code> is not found</b>") await message.edit(f"<b>Module <code>{module_name}</code> is not found</b>")
            return return
        if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"):
            os.mkdir(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: with open(f"./modules/custom_modules/{module_name}.py", "wb") as f:
            f.write(resp.content) f.write(resp.content)
    else: else:
        file_name = await message.reply_to_message.download() file_name = await message.reply_to_message.download()
        module_name = message.reply_to_message.document.file_name[:-3] module_name = message.reply_to_message.document.file_name[:-3]
        with open(file_name, "rb") as f: with open(file_name, "rb") as f:
            content = f.read() content = f.read()
        modules_hashes = requests.get( modules_hashes = requests.get(
            "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt" "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt"
        ).text ).text
        if hashlib.sha256(content).hexdigest() not in modules_hashes: if hashlib.sha256(content).hexdigest() not in modules_hashes:
            os.remove(file_name) os.remove(file_name)
            return await message.edit( return await message.edit(
                "<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>" "<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>"
                "verified</a> modules or from the official " "verified</a> modules or from the official "
                "<a href=https://github.com/The-MoonTg-project/custom_modules>" "<a href=https://github.com/The-MoonTg-project/custom_modules>"
                "custom_modules</a> repository are supported!</b>", "custom_modules</a> repository are supported!</b>",
                disable_web_page_preview=True, disable_web_page_preview=True,
            ) )
        else: else:
            os.rename(file_name, f"./modules/custom_modules/{module_name}.py") os.rename(file_name, f"./modules/custom_modules/{module_name}.py")
    await message.edit(f"<b>The module <code>{module_name}</code> is loaded!</b>") await message.edit(f"<b>The module <code>{module_name}</code> is loaded!</b>")
    restart() restart()
@Client.on_message(filters.command(["unloadmod", "ulm"], prefix) & filters.me) @Client.on_message(filters.command(["unloadmod", "ulm"], prefix) & filters.me)
async def unload_mods(_, message: Message): async def unload_mods(_, message: Message):
    if len(message.command) <= 1: if len(message.command) <= 1:
        return return
    module_name = message.command[1].lower() module_name = message.command[1].lower()
    if module_name.startswith( if module_name.startswith(
        "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/" "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/"
    ): ):
        module_name = module_name.split("/")[-1].split(".")[0] module_name = module_name.split("/")[-1].split(".")[0]
    if os.path.exists(f"{BASE_PATH}/modules/custom_modules/{module_name}.py"): if os.path.exists(f"{BASE_PATH}/modules/custom_modules/{module_name}.py"):
        os.remove(f"{BASE_PATH}/modules/custom_modules/{module_name}.py") os.remove(f"{BASE_PATH}/modules/custom_modules/{module_name}.py")
        await message.edit(f"<b>The module <code>{module_name}</code> removed!</b>") await message.edit(f"<b>The module <code>{module_name}</code> removed!</b>")
        restart() restart()
    elif os.path.exists(f"{BASE_PATH}/modules/{module_name}.py"): elif os.path.exists(f"{BASE_PATH}/modules/{module_name}.py"):
        await message.edit( await message.edit(
            "<b>It is forbidden to remove built-in modules, it will disrupt the updater</b>" "<b>It is forbidden to remove built-in modules, it will disrupt the updater</b>"
        ) )
    else: else:
        await message.edit(f"<b>Module <code>{module_name}</code> is not found</b>") await message.edit(f"<b>Module <code>{module_name}</code> is not found</b>")
@Client.on_message(filters.command(["loadallmods"], prefix) & filters.me) @Client.on_message(filters.command(["loadallmods"], prefix) & filters.me)
async def load_all_mods(_, message: Message): async def load_all_mods(_, message: Message):
    await message.edit("<b>Fetching info...</b>") await message.edit("<b>Fetching info...</b>")
    if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"):
        os.mkdir(f"{BASE_PATH}/modules/custom_modules") os.mkdir(f"{BASE_PATH}/modules/custom_modules")
    modules_list = requests.get( modules_list = requests.get(
        "https://api.github.com/repos/The-MoonTg-project/custom_modules/contents/" "https://api.github.com/repos/The-MoonTg-project/custom_modules/contents/"
    ).json() ).json()
    new_modules = {} new_modules = {}
    for module_info in modules_list: for module_info in modules_list:
        if not module_info["name"].endswith(".py"): if not module_info["name"].endswith(".py"):
            continue continue
        if os.path.exists(f'{BASE_PATH}/modules/custom_modules/{module_info["name"]}'): if os.path.exists(f'{BASE_PATH}/modules/custom_modules/{module_info["name"]}'):
            continue continue
        new_modules[module_info["name"][:-3]] = module_info["download_url"] new_modules[module_info["name"][:-3]] = module_info["download_url"]
    if not new_modules: if not new_modules:
        return await message.edit("<b>All modules already loaded</b>") return await message.edit("<b>All modules already loaded</b>")
    await message.edit(f'<b>Loading new modules: {" ".join(new_modules.keys())}</b>') await message.edit(f'<b>Loading new modules: {" ".join(new_modules.keys())}</b>')
    for name, url in new_modules.items(): for name, url in new_modules.items():
        with open(f"./modules/custom_modules/{name}.py", "wb") as f: with open(f"./modules/custom_modules/{name}.py", "wb") as f:
            f.write(requests.get(url).content) f.write(requests.get(url).content)
    await message.edit( await message.edit(
        f'<b>Successfully loaded new modules: {" ".join(new_modules.keys())}</b>' f'<b>Successfully loaded new modules: {" ".join(new_modules.keys())}</b>'
    ) )
    restart() restart()
@Client.on_message(filters.command(["updateallmods"], prefix) & filters.me) @Client.on_message(filters.command(["updateallmods"], prefix) & filters.me)
async def updateallmods(_, message: Message): async def updateallmods(_, message: Message):
    await message.edit("<b>Updating modules...</b>") await message.edit("<b>Updating modules...</b>")
    if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"): if not os.path.exists(f"{BASE_PATH}/modules/custom_modules"):
        os.mkdir(f"{BASE_PATH}/modules/custom_modules") os.mkdir(f"{BASE_PATH}/modules/custom_modules")
    modules_installed = list(os.walk("modules/custom_modules"))[0][2] modules_installed = list(os.walk("modules/custom_modules"))[0][2]
    if not modules_installed: if not modules_installed:
        return await message.edit("<b>You don't have any modules installed</b>") return await message.edit("<b>You don't have any modules installed</b>")
    for module_name in modules_installed: for module_name in modules_installed:
        if not module_name.endswith(".py"): if not module_name.endswith(".py"):
            continue continue
        resp = requests.get( resp = requests.get(
            f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}" f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}"
        ) )
        if not resp.ok: if not resp.ok:
            modules_installed.remove(module_name) modules_installed.remove(module_name)
            continue continue
        with open(f"./modules/custom_modules/{module_name}", "wb") as f: with open(f"./modules/custom_modules/{module_name}", "wb") as f:
            f.write(resp.content) f.write(resp.content)
    await message.edit(f"<b>Successfully updated {len(modules_installed)} modules</b>") await message.edit(f"<b>Successfully updated {len(modules_installed)} modules</b>")
modules_help["loader"] = { modules_help["loader"] = {
    "loadmod [module_name]*": "Download module.\n" "loadmod [module_name]*": "Download module.\n"
    "Only modules from the official custom_modules repository and proven " "Only modules from the official custom_modules repository and proven "
    "modules whose hashes are in modules_hashes.txt are supported", "modules whose hashes are in modules_hashes.txt are supported",
    "unloadmod [module_name]*": "Delete module", "unloadmod [module_name]*": "Delete module",
    "modhash [link]*": "Get module hash by link", "modhash [link]*": "Get module hash by link",
    "loadallmods": "Load all custom modules (use it at your own risk)", "loadallmods": "Load all custom modules (use it at your own risk)",
    "updateallmods": "Update all custom modules", "updateallmods": "Update all custom modules",
} }

View File

@@ -29,7 +29,7 @@ if ! command -v termux-setup-storage; then
echo echo
echo "Enter API_ID and API_HASH" 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)" echo "Leave empty to use defaults  (please note that default keys significantly increases your ban chances)"
read -r -p "API_ID > " api_id read -r -p "API_ID > " api_id

View File

@@ -1,170 +1,170 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import json import json
import threading import threading
import dns.resolver import dns.resolver
import pymongo import pymongo
import sqlite3 import sqlite3
from utils import config from utils import config
dns.resolver.default_resolver = dns.resolver.Resolver(configure=False) dns.resolver.default_resolver = dns.resolver.Resolver(configure=False)
dns.resolver.default_resolver.nameservers = ["8.8.8.8"] dns.resolver.default_resolver.nameservers = ["8.8.8.8"]
class Database: class Database:
    def get(self, module: str, variable: str, default=None): def get(self, module: str, variable: str, default=None):
        """Get value from database""" """Get value from database"""
        raise NotImplementedError raise NotImplementedError
    def set(self, module: str, variable: str, value): def set(self, module: str, variable: str, value):
        """Set key in database""" """Set key in database"""
        raise NotImplementedError raise NotImplementedError
    def remove(self, module: str, variable: str): def remove(self, module: str, variable: str):
        """Remove key from database""" """Remove key from database"""
        raise NotImplementedError raise NotImplementedError
    def get_collection(self, module: str) -> dict: def get_collection(self, module: str) -> dict:
        """Get database for selected module""" """Get database for selected module"""
        raise NotImplementedError raise NotImplementedError
    def close(self): def close(self):
        """Close the database""" """Close the database"""
        raise NotImplementedError raise NotImplementedError
class MongoDatabase(Database): class MongoDatabase(Database):
    def __init__(self, url, name): def __init__(self, url, name):
        self._client = pymongo.MongoClient(url) self._client = pymongo.MongoClient(url)
        self._database = self._client[name] self._database = self._client[name]
    def set(self, module: str, variable: str, value): def set(self, module: str, variable: str, value):
        self._database[module].replace_one( self._database[module].replace_one(
            {"var": variable}, {"var": variable, "val": value}, upsert=True {"var": variable}, {"var": variable, "val": value}, upsert=True
        ) )
    def get(self, module: str, variable: str, expected_value=None): def get(self, module: str, variable: str, expected_value=None):
        doc = self._database[module].find_one({"var": variable}) doc = self._database[module].find_one({"var": variable})
        return expected_value if doc is None else doc["val"] return expected_value if doc is None else doc["val"]
    def get_collection(self, module: str): def get_collection(self, module: str):
        return {item["var"]: item["val"] for item in self._database[module].find()} return {item["var"]: item["val"] for item in self._database[module].find()}
    def remove(self, module: str, variable: str): def remove(self, module: str, variable: str):
        self._database[module].delete_one({"var": variable}) self._database[module].delete_one({"var": variable})
    def close(self): def close(self):
        self._client.close() self._client.close()
class SqliteDatabase(Database): class SqliteDatabase(Database):
    def __init__(self, file): def __init__(self, file):
        self._conn = sqlite3.connect(file, check_same_thread=False) self._conn = sqlite3.connect(file, check_same_thread=False)
        self._conn.row_factory = sqlite3.Row self._conn.row_factory = sqlite3.Row
        self._cursor = self._conn.cursor() self._cursor = self._conn.cursor()
        self._lock = threading.Lock() self._lock = threading.Lock()
    @staticmethod @staticmethod
    def _parse_row(row: sqlite3.Row): def _parse_row(row: sqlite3.Row):
        if row["type"] == "bool": if row["type"] == "bool":
            return row["val"] == "1" return row["val"] == "1"
        elif row["type"] == "int": elif row["type"] == "int":
            return int(row["val"]) return int(row["val"])
        elif row["type"] == "str": elif row["type"] == "str":
            return row["val"] return row["val"]
        else: else:
            return json.loads(row["val"]) return json.loads(row["val"])
    def _execute(self, module: str, *args, **kwargs) -> sqlite3.Cursor: def _execute(self, module: str, *args, **kwargs) -> sqlite3.Cursor:
        self._lock.acquire() self._lock.acquire()
        try: try:
            return self._cursor.execute(*args, **kwargs) return self._cursor.execute(*args, **kwargs)
        except sqlite3.OperationalError as e: except sqlite3.OperationalError as e:
            if str(e).startswith("no such table"): if str(e).startswith("no such table"):
                sql = f""" sql = f"""
                CREATE TABLE IF NOT EXISTS '{module}' ( CREATE TABLE IF NOT EXISTS '{module}' (
                var TEXT UNIQUE NOT NULL, var TEXT UNIQUE NOT NULL,
                val TEXT NOT NULL, val TEXT NOT NULL,
                type TEXT NOT NULL type TEXT NOT NULL
                ) )
                """ """
                self._cursor.execute(sql) self._cursor.execute(sql)
                self._conn.commit() self._conn.commit()
                return self._cursor.execute(*args, **kwargs) return self._cursor.execute(*args, **kwargs)
            raise e from None raise e from None
        finally: finally:
            self._lock.release() self._lock.release()
    def get(self, module: str, variable: str, default=None): def get(self, module: str, variable: str, default=None):
        sql = f"SELECT * FROM '{module}' WHERE var=:var" sql = f"SELECT * FROM '{module}' WHERE var=:var"
        cur = self._execute(module, sql, {"tabl": module, "var": variable}) cur = self._execute(module, sql, {"tabl": module, "var": variable})
        row = cur.fetchone() row = cur.fetchone()
        if row is None: if row is None:
            return default return default
        else: else:
            return self._parse_row(row) return self._parse_row(row)
    def set(self, module: str, variable: str, value) -> bool: def set(self, module: str, variable: str, value) -> bool:
        sql = f""" sql = f"""
        INSERT INTO '{module}' VALUES ( :var, :val, :type ) INSERT INTO '{module}' VALUES ( :var, :val, :type )
        ON CONFLICT (var) DO ON CONFLICT (var) DO
        UPDATE SET val=:val, type=:type WHERE var=:var UPDATE SET val=:val, type=:type WHERE var=:var
        """ """
        if isinstance(value, bool): if isinstance(value, bool):
            val = "1" if value else "0" val = "1" if value else "0"
            typ = "bool" typ = "bool"
        elif isinstance(value, str): elif isinstance(value, str):
            val = value val = value
            typ = "str" typ = "str"
        elif isinstance(value, int): elif isinstance(value, int):
            val = str(value) val = str(value)
            typ = "int" typ = "int"
        else: else:
            val = json.dumps(value) val = json.dumps(value)
            typ = "json" typ = "json"
        self._execute(module, sql, {"var": variable, "val": val, "type": typ}) self._execute(module, sql, {"var": variable, "val": val, "type": typ})
        self._conn.commit() self._conn.commit()
        return True return True
    def remove(self, module: str, variable: str): def remove(self, module: str, variable: str):
        sql = f"DELETE FROM '{module}' WHERE var=:var" sql = f"DELETE FROM '{module}' WHERE var=:var"
        self._execute(module, sql, {"var": variable}) self._execute(module, sql, {"var": variable})
        self._conn.commit() self._conn.commit()
    def get_collection(self, module: str) -> dict: def get_collection(self, module: str) -> dict:
        sql = f"SELECT * FROM '{module}'" sql = f"SELECT * FROM '{module}'"
        cur = self._execute(module, sql) cur = self._execute(module, sql)
        collection = {} collection = {}
        for row in cur: for row in cur:
            collection[row["var"]] = self._parse_row(row) collection[row["var"]] = self._parse_row(row)
        return collection return collection
    def close(self): def close(self):
        self._conn.commit() self._conn.commit()
        self._conn.close() self._conn.close()
if config.db_type in ["mongo", "mongodb"]: if config.db_type in ["mongo", "mongodb"]:
    db = MongoDatabase(config.db_url, config.db_name) db = MongoDatabase(config.db_url, config.db_name)
else: else:
    db = SqliteDatabase(config.db_name) db = SqliteDatabase(config.db_name)

View File

@@ -1,44 +1,45 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from sys import version_info from sys import version_info
from .db import db from .db import db
from git import Repo from git import Repo
class ModulesHelpDict(dict): class ModulesHelpDict(dict):
    def append(self, obj: dict): def append(self, obj: dict):
        # convert help from old to new type # convert help from old to new type
        module_name = list(obj.keys())[0] module_name = list(obj.keys())[0]
        cmds = obj[module_name] cmds = obj[module_name]
        commands = {} commands = {}
        for cmd in cmds: for cmd in cmds:
            cmd_name = list(cmd.keys())[0] cmd_name = list(cmd.keys())[0]
            cmd_desc = cmd[cmd_name] cmd_desc = cmd[cmd_name]
            commands[cmd_name] = cmd_desc commands[cmd_name] = cmd_desc
        self[module_name] = commands self[module_name] = commands
modules_help = ModulesHelpDict() modules_help = ModulesHelpDict()
requirements_list = [] requirements_list = []
python_version = f"{version_info[0]}.{version_info[1]}.{version_info[2]}" python_version = f"{version_info[0]}.{version_info[1]}.{version_info[2]}"
prefix = db.get("core.main", "prefix", ".") prefix = db.get("core.main", "prefix", ".")
gitrepo = Repo(".") gitrepo = Repo(".")
commits_since_tag = list(gitrepo.iter_commits(f"{gitrepo.tags[-1].name}..HEAD")) commits_since_tag = list(gitrepo.iter_commits(
userbot_version = f"3.1.{len(commits_since_tag)}" f"{gitrepo.tags[-1].name}..HEAD"))
userbot_version = f"3.1.{len(commits_since_tag)}"

View File

@@ -1,18 +1,18 @@
#  Moon-Userbot - telegram userbot # Moon-Userbot - telegram userbot
#  Copyright (C) 2020-present Moon Userbot Organization # Copyright (C) 2020-present Moon Userbot Organization
# #
#  This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version. # (at your option) any later version.
#  This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details. # GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import asyncio import asyncio
import os import os
import sys import sys
@@ -28,173 +28,137 @@ from .misc import modules_help, prefix, requirements_list
def text(message: types.Message): 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(): 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): def format_exc(e: Exception, hint: str = None):
traceback.print_exc() traceback.print_exc()
if isinstance(e, errors.RPCError): if isinstance(e, errors.RPCError):
return ( return (
f"<b>Telegram API error!</b>\n" f"<b>Telegram API error!</b>\n"
f"<code>[ { f"<code>[{e.CODE} {e.ID or e.NAME}] - {e.MESSAGE}</code>"
e.CODE )
}  { else:
e.ID or e.NAME if hint:
}] -  { hint_text = f"\n\n<b>Hint: {hint}</b>"
e.MESSAGE else:
}</code>" hint_text = ""
) return (
else : f"<b>Error!</b>\n" f"<code>{e.__class__.__name__}: {e}</code>" + hint_text
if hint: )
hint_text = f"\n\n<b>Hint:  {
hint
}</b>"
else :
hint_text = ""
return (
f"<b>Error!</b>\n" f"<code> {
e.__class__.__name__
}:  {
e
}</code>" + hint_text
)
def with_reply(func): def with_reply(func):
async def wrapped(client: Client, message: types.Message): async def wrapped(client: Client, message: types.Message):
if not message.reply_to_message: if not message.reply_to_message:
await message.edit("<b>Reply to message is required</b>") await message.edit("<b>Reply to message is required</b>")
else : else:
return await func(client, message) return await func(client, message)
return wrapped return wrapped
async def interact_with(message: types.Message) -> types.Message: async def interact_with(message: types.Message) -> types.Message:
""" """
    Check history with bot and return bot's response Check history with bot and return bot's response
    Example: Example:
    .. code-block:: python .. code-block:: python
        bot_msg = await interact_with(await bot.send_message("@BotFather", "/start")) bot_msg = await interact_with(await bot.send_message("@BotFather", "/start"))
    :param message: already sent message to bot :param message: already sent message to bot
    :return: bot's response :return: bot's response
    """ """
await asyncio.sleep(1) await asyncio.sleep(1)
# noinspection PyProtectedMember # noinspection PyProtectedMember
response = await message._client.get_history(message.chat.id, limit = 1) response = await message._client.get_history(message.chat.id, limit=1)
seconds_waiting = 0 seconds_waiting = 0
while response[0].from_user.is_self: while response[0].from_user.is_self:
seconds_waiting += 1 seconds_waiting += 1
if seconds_waiting >= 5: if seconds_waiting >= 5:
raise RuntimeError("bot didn't answer in 5 seconds") raise RuntimeError("bot didn't answer in 5 seconds")
await asyncio.sleep(1) await asyncio.sleep(1)
# noinspection PyProtectedMember # noinspection PyProtectedMember
response = await message._client.get_history(message.chat.id, limit = 1) response = await message._client.get_history(message.chat.id, limit=1)
interact_with_to_delete.append(message.message_id) interact_with_to_delete.append(message.message_id)
interact_with_to_delete.append(response[0].message_id) interact_with_to_delete.append(response[0].message_id)
return response[0] return response[0]
interact_with_to_delete = [] interact_with_to_delete = []
def format_module_help(module_name: str): def format_module_help(module_name: str):
commands = modules_help[module_name] commands = modules_help[module_name]
help_text = f"<b>Help for | { help_text = f"<b>Help for |{module_name}|\n\nUsage:</b>\n"
module_name
}|\n\nUsage:</b>\n"
for command, desc in commands.items(): for command, desc in commands.items():
cmd = command.split(maxsplit = 1) cmd = command.split(maxsplit=1)
args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else "" args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else ""
help_text += f"<code> { help_text += f"<code>{prefix}{cmd[0]}</code>{args} — <i>{desc}</i>\n"
prefix
} {
cmd[0]}</code> {
args
} — <i> {
desc
}</i>\n"
return help_text return help_text
def format_small_module_help(module_name: str): def format_small_module_help(module_name: str):
commands = modules_help[module_name] commands = modules_help[module_name]
help_text = f"<b>Help for | { help_text = f"<b>Help for |{module_name}|\n\nCommands list:\n"
module_name for command, desc in commands.items():
}|\n\nCommands list:\n" cmd = command.split(maxsplit=1)
for command, desc in commands.items(): args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else ""
cmd = command.split(maxsplit = 1) help_text += f"<code>{prefix}{cmd[0]}</code>{args}\n"
args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else "" help_text += f"\nGet full usage: <code>{prefix}help {module_name}</code></b>"
help_text += f"<code> {
prefix
} {
cmd[0]}</code> {
args
}\n"
help_text += f"\nGet full usage: <code> {
prefix
}help  {
module_name
}</code></b>"
return help_text return help_text
def import_library(library_name: str, package_name: str = None): def import_library(library_name: str, package_name: str = None):
""" """
    Loads a library, or installs it in ImportError case Loads a library, or installs it in ImportError case
    :param library_name: library name (import example...) :param library_name: library name (import example...)
    :param package_name: package name in PyPi (pip install example) :param package_name: package name in PyPi (pip install example)
    :return: loaded module :return: loaded module
    """ """
if package_name is None: if package_name is None:
package_name = library_name package_name = library_name
requirements_list.append(package_name) requirements_list.append(package_name)
try: try:
return importlib.import_module(library_name) return importlib.import_module(library_name)
except ImportError: except ImportError:
completed = subprocess.run(["python3", "-m", "pip", "install", package_name]) completed = subprocess.run(
if completed.returncode != 0: ["python3", "-m", "pip", "install", package_name])
raise AssertionError( if completed.returncode != 0:
f"Failed to install library  { raise AssertionError(
package_name f"Failed to install library {package_name} (pip exited with code {completed.returncode})"
} (pip exited with code  { )
completed.returncode return importlib.import_module(library_name)
})"
)
return importlib.import_module(library_name)
def resize_image(input_img, output = None, img_type = "PNG"): def resize_image(input_img, output=None, img_type="PNG"):
if output is None: if output is None:
output = BytesIO() output = BytesIO()
output.name = f"sticker. { output.name = f"sticker.{img_type.lower()}"
img_type.lower()}"
with Image.open(input_img) as img: with Image.open(input_img) as img:
# We used to use thumbnail(size) here, but it returns with a *max* dimension of 512,512 # 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 :( # rather than making one side exactly 512 so we have to calculate dimensions manually :(
if img.width == img.height: if img.width == img.height:
size = (512, 512) size = (512, 512)
elif img.width < img.height: elif img.width < img.height:
size = (max(512 * img.width // img.height, 1), 512) size = (max(512 * img.width // img.height, 1), 512)
else : else:
size = (512, max(512 * img.height // img.width, 1)) 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 return output