├── .gitignore
├── Dockerfile.sample
├── LICENSE
├── Procfile
├── PyrogramBot
├── __init__.py
├── __main__.py
├── config.py
├── db
│ ├── README.md
│ ├── chatsdb
│ ├── filtersdb
│ ├── gbansdb
│ ├── notesdb
│ └── warnsdb
├── modules
│ ├── __init__.py
│ ├── __main__.py
│ ├── eval.py
│ ├── fun.py
│ ├── ping.py
│ └── start.py
└── utils
│ ├── errors.py
│ └── misc.py
├── README.md
├── app.json
├── heroku.yml.sample
├── requirements.txt
└── runtime.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | token.py
2 | *.raw
3 | images/
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *.png
8 | *.mp4
9 | *.webm
10 | *$py.class
11 | *.mp3
12 | .
13 | # C extensions
14 | *.so
15 | config.py
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | pip-wheel-metadata/
31 | share/python-wheels/
32 | *.egg-info/
33 | .installed.cfg
34 | *.egg
35 | MANIFEST
36 |
37 | # PyInstaller
38 | # Usually these files are written by a python script from a template
39 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
40 | *.manifest
41 | *.spec
42 |
43 | # Installer logs
44 | pip-log.txt
45 | pip-delete-this-directory.txt
46 |
47 | # Unit test / coverage reports
48 | htmlcov/
49 | .tox/
50 | .nox/
51 | .coverage
52 | .coverage.*
53 | .cache
54 | nosetests.xml
55 | coverage.xml
56 | *.cover
57 | *.py,cover
58 | .hypothesis/
59 | .pytest_cache/
60 |
61 | # Translations
62 | *.mo
63 | *.pot
64 |
65 | # Django stuff:
66 | *.log
67 | local_settings.py
68 | db.sqlite3
69 | db.sqlite3-journal
70 |
71 | # Flask stuff:
72 | instance/
73 | .webassets-cache
74 |
75 | # Scrapy stuff:
76 | .scrapy
77 |
78 | # Sphinx documentation
79 | docs/_build/
80 |
81 | # PyBuilder
82 | target/
83 |
84 | # Jupyter Notebook
85 | .ipynb_checkpoints
86 |
87 | # IPython
88 | profile_default/
89 | ipython_config.py
90 |
91 | # pyenv
92 | .python-version
93 |
94 | # pipenv
95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
98 | # install all needed dependencies.
99 | #Pipfile.lock
100 |
101 | # celery beat schedule file
102 | celerybeat-schedule
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 | *.ini
134 | *.pyc
135 | *.session
136 | *.session-journal
137 |
138 | # vim
139 | [._]*.sw[a-p]
140 |
141 | #others
142 | neofetch.txt
143 | error.log
144 | permissions.json
145 | .vscode
--------------------------------------------------------------------------------
/Dockerfile.sample:
--------------------------------------------------------------------------------
1 | FROM ubuntu:latest
2 |
3 | WORKDIR /usr/src/app
4 | RUN chmod 777 /usr/src/app
5 | RUN apt-get -qq update
6 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -qq install python3 python3-pip software-properties-common
7 |
8 | #Updating Libraries
9 | RUN pip3 install -U pip
10 | COPY requirements.txt .
11 | RUN pip3 install --no-cache-dir -U -r requirements.txt
12 |
13 | #Copying All Source
14 | COPY . .
15 |
16 | #Starting Bot
17 | CMD ["python3", "-m", "PyrogramBot"]
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 MaskedVirus | swatv3nub
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python3 -m PyrogramBot
2 |
--------------------------------------------------------------------------------
/PyrogramBot/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import time
3 | import os
4 | import sys
5 | from pyrogram import Client, errors
6 | from .config import API_ID, API_HASH, BOT_TOKEN
7 | #from .config import MONGO_DB_URI
8 |
9 | # Adding Mongo Example
10 |
11 | # from motor.motor_asyncio import AsyncIOMotorClient as MongoClient
12 |
13 | LOAD_MODULES = []
14 | NOLOAD_MODULES = []
15 | StartTime = time.time()
16 | logging.basicConfig(level=logging.INFO)
17 |
18 | if sys.version_info[0] < 3 or sys.version_info[1] < 8:
19 | LOGGER.error(
20 | (
21 | "You MUST have a Python Version of at least 3.8!\n"
22 | "Multiple features depend on this. Aborting The Deploy!"
23 | )
24 | )
25 | quit(1)
26 |
27 | app = Client("pyrogrambot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)
28 |
29 | bot_start_time = time.time()
30 |
31 | # mongodb = MongoClient(MONGO_DB_URI)
32 | # db = mongodb.pyrogrambot
33 |
--------------------------------------------------------------------------------
/PyrogramBot/__main__.py:
--------------------------------------------------------------------------------
1 | from pyrogram import idle, Client
2 |
3 | from pyrogrambot import app, filters
4 | from pyrogrambot.utils.misc import count_modules
5 |
6 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
7 |
8 | import importlib
9 | import re
10 |
11 | #Bot info
12 |
13 | async def get_info(app):
14 | global BOT_ID, BOT_NAME, BOT_USERNAME, BOT_DC_ID
15 | getme = await app.get_me()
16 | BOT_ID = getme.id
17 |
18 | if getme.last_name:
19 | BOT_NAME = getme.first_name + " " + getme.last_name
20 | else:
21 | BOT_NAME = getme.first_name
22 | BOT_USERNAME = getme.username
23 | BOT_DC_ID = getme.dc_id
24 |
25 | #Help [Taken From WBB]
26 |
27 | HELPABLE = {}
28 |
29 |
30 | async def start_bot():
31 | await app.start()
32 | await get_info(app)
33 |
34 | for module in ALL_MODULES:
35 | imported_module = importlib.import_module("PyrogramBot.modules." + module)
36 | if (
37 | hasattr(imported_module, "__MODULE__")
38 | and imported_module.__MODULE__
39 | ):
40 | imported_module.__MODULE__ = imported_module.__MODULE__
41 | if (
42 | hasattr(imported_module, "__HELP__")
43 | and imported_module.__HELP__
44 | ):
45 | HELPABLE[
46 | imported_module.__MODULE__.lower()
47 | ] = imported_module
48 |
49 | bot_modules = ""
50 | j = 1
51 | for i in ALL_MODULES:
52 | if j == 4:
53 | bot_modules += "|{:<15}|\n".format(i)
54 | j = 0
55 | else:
56 | bot_modules += "|{:<15}".format(i)
57 | j += 1
58 | print(">>------------|•|-----------<<")
59 | print(f">>------|• {BOT_NAME} •|-----<<")
60 | print(">>------------|•|-----------<<")
61 | print(bot_modules)
62 | print("Bot is Up, Game ON!!")
63 | await idle()
64 |
65 |
66 |
67 |
68 | @app.on_message(filters.command("help"))
69 | async def help_command(_, message):
70 | if message.chat.type != "private":
71 | if len(message.command) >= 2 and message.command[1] == "help":
72 | text, keyboard = await help_parser(message)
73 | await message.reply(
74 | text, reply_markup=keyboard, disable_web_page_preview=True
75 | )
76 | return
77 | keyboard = InlineKeyboardMarkup(
78 | [
79 | [
80 | InlineKeyboardButton(
81 | text="Help",
82 | url=f"t.me/{BOT_USERNAME}?start=help",
83 | )
84 | ]
85 | ]
86 | )
87 | await message.reply("Contact me in PM.", reply_markup=keyboard)
88 | return
89 | text, keyboard = await help_parser(message)
90 | await message.reply_text(text, reply_markup=keyboard)
91 |
92 |
93 | async def help_parser(message, keyboard=None):
94 | if not keyboard:
95 | keyboard = InlineKeyboardMarkup(count_modules(0, HELPABLE, "help"))
96 | return (
97 | "Hi {first_name}, I am a bot".format(
98 | first_name=message.from_user.first_name,
99 | ),
100 | keyboard,
101 | )
102 |
103 |
104 | @app.on_callback_query(filters.regex(r"help_(.*?)"))
105 | async def help_button(client, query):
106 | mod_match = re.match(r"help_module\((.+?)\)", query.data)
107 | prev_match = re.match(r"help_prev\((.+?)\)", query.data)
108 | next_match = re.match(r"help_next\((.+?)\)", query.data)
109 | back_match = re.match(r"help_back", query.data)
110 | create_match = re.match(r"help_create", query.data)
111 |
112 | if mod_match:
113 | module = mod_match.group(1)
114 | text = (
115 | "{} **{}**:\n".format(
116 | "Here is the help for", HELPABLE[module].__MODULE__
117 | )
118 | + HELPABLE[module].__HELP__
119 | )
120 |
121 | await query.message.edit(
122 | text=text,
123 | reply_markup=InlineKeyboardMarkup(
124 | [[InlineKeyboardButton("back", callback_data="help_back")]]
125 | ),
126 | disable_web_page_preview=True,
127 | )
128 |
129 | elif prev_match:
130 | curr_page = int(prev_match.group(1))
131 | await query.message.edit(
132 | text="Hi {first_name}. I am bot".format(
133 | first_name=query.from_user.first_name,
134 | ),
135 | reply_markup=InlineKeyboardMarkup(
136 | count_modules(curr_page - 1, HELPABLE, "help")
137 | ),
138 | disable_web_page_preview=True,
139 | )
140 |
141 | elif next_match:
142 | next_page = int(next_match.group(1))
143 | await query.message.edit(
144 | text="Hi {first_name}. I am a bot".format(
145 | first_name=query.from_user.first_name,
146 | ),
147 | reply_markup=InlineKeyboardMarkup(
148 | count_modules(next_page + 1, HELPABLE, "help")
149 | ),
150 | disable_web_page_preview=True,
151 | )
152 |
153 | elif back_match:
154 | await query.message.edit(
155 | text="Hi {first_name}. I am a bot".format(
156 | first_name=query.from_user.first_name,
157 | ),
158 | reply_markup=InlineKeyboardMarkup(
159 | count_modules(0, HELPABLE, "help")
160 | ),
161 | disable_web_page_preview=True,
162 | )
163 |
164 | elif create_match:
165 | text, keyboard = await help_parser(query)
166 | await query.message.edit(
167 | text=text, reply_markup=keyboard, disable_web_page_preview=True
168 | )
169 |
170 | return await client.answer_callback_query(query.id)
171 |
172 |
173 |
174 | if __name__ == "__main__":
175 | app.start()
176 | idle()
177 |
--------------------------------------------------------------------------------
/PyrogramBot/config.py:
--------------------------------------------------------------------------------
1 | BOT_TOKEN = "16383:BSNSJS"
2 | API_ID = 69
3 | API_HASH = "HSJSN7288KSNEJD"
4 | #MONGO_DB_URI = "mongodb+srv://username:password@cluster0.ksiis.mongodb.net/YourDataBaseName?retryWrites=true&w=majority"
5 |
--------------------------------------------------------------------------------
/PyrogramBot/db/README.md:
--------------------------------------------------------------------------------
1 | All The Database Codes are taken from [Akshay Rajput](https://t.me/TheHamkerCat)'s [WilliamButcherBot](https://github.com/TheHamkerCat/WilliamButcherBot.git)'s Repo
2 |
3 | Complete Authorship of Database Codes to Akshay.
4 |
5 | **NOTE:** I didn't Gave File Extensions in db files.
6 | If you want to use Them, Edit the File names with *.py extension.
7 |
--------------------------------------------------------------------------------
/PyrogramBot/db/chatsdb:
--------------------------------------------------------------------------------
1 | from PyrogramBot import db
2 | from typing import List
3 |
4 |
5 | chatsdb = db.chats
6 |
7 |
8 | async def is_in_chat(chat_id: int) -> bool:
9 | chat = await chatsdb.find_one({"chat_id": chat_id})
10 | if not chat:
11 | return False
12 | return True
13 |
14 |
15 | async def get_in_chats() -> list:
16 | chats = chatsdb.find({"chat_id": {'$lt': 0}})
17 | if not chats:
18 | return []
19 | chats_list = []
20 | for chat in await chats.to_list(length=1000000000):
21 | chats_list.append(chat)
22 | return chats_list
23 |
24 |
25 | async def add_in_chat(chat_id: int):
26 | is_in = await is_in_chat(chat_id)
27 | if is_in:
28 | return
29 | return await chatsdb.insert_one({"chat_id": chat_id})
30 |
31 |
32 | async def remove_in_chat(chat_id: int):
33 | is_in = await is_in_chat(chat_id)
34 | if not is_in:
35 | return
36 | return await chatsdb.delete_one({"chat_id": chat_id})
--------------------------------------------------------------------------------
/PyrogramBot/db/filtersdb:
--------------------------------------------------------------------------------
1 | from PyrogramBot import db
2 | from typing import Dict, List, Union
3 |
4 | filtersdb = db.filters
5 |
6 | async def get_filters_count() -> dict:
7 | chats = filtersdb.find({"chat_id": {"$lt": 0}})
8 | if not chats:
9 | return {}
10 | chats_count = 0
11 | filters_count = 0
12 | for chat in await chats.to_list(length=1000000000):
13 | filters_name = await get_filters_names(chat['chat_id'])
14 | filters_count += len(filters_name)
15 | chats_count += 1
16 | return {
17 | "chats_count": chats_count,
18 | "filters_count": filters_count
19 | }
20 |
21 |
22 | async def _get_filters(chat_id: int) -> Dict[str, int]:
23 | _filters = await filtersdb.find_one({"chat_id": chat_id})
24 | if _filters:
25 | _filters = _filters['filters']
26 | else:
27 | _filters = {}
28 | return _filters
29 |
30 |
31 | async def get_filters_names(chat_id: int) -> List[str]:
32 | _filters = []
33 | for _filter in await _get_filters(chat_id):
34 | _filters.append(_filter)
35 | return _filters
36 |
37 |
38 | async def get_filter(chat_id: int, name: str) -> Union[bool, dict]:
39 | name = name.lower().strip()
40 | _filters = await _get_filters(chat_id)
41 | if name in _filters:
42 | return _filters[name]
43 | else:
44 | return False
45 |
46 |
47 | async def save_filter(chat_id: int, name: str, _filter: dict):
48 | name = name.lower().strip()
49 | _filters = await _get_filters(chat_id)
50 | _filters[name] = _filter
51 | await filtersdb.update_one(
52 | {"chat_id": chat_id},
53 | {
54 | "$set": {
55 | "filters": _filters
56 | }
57 | },
58 | upsert=True
59 | )
60 |
61 |
62 | async def delete_filter(chat_id: int, name: str) -> bool:
63 | filtersd = await _get_filters(chat_id)
64 | name = name.lower().strip()
65 | if name in filtersd:
66 | del filtersd[name]
67 | await filtersdb.update_one(
68 | {"chat_id": chat_id},
69 | {
70 | "$set": {
71 | "filters": filtersd
72 | }
73 | },
74 | upsert=True
75 | )
76 | return True
77 | return False
--------------------------------------------------------------------------------
/PyrogramBot/db/gbansdb:
--------------------------------------------------------------------------------
1 | from PyrogramBot import db
2 |
3 |
4 | gbansdb = db.gban
5 |
6 |
7 | async def get_gbans_count() -> int:
8 | users = gbansdb.find({"user_id": {"$gt": 0}})
9 | users = await users.to_list(length=100000)
10 | return len(users)
11 |
12 |
13 | async def is_gbanned_user(user_id: int) -> bool:
14 | user = await gbansdb.find_one({"user_id": user_id})
15 | if not user:
16 | return False
17 | return True
18 |
19 |
20 | async def add_gban_user(user_id: int):
21 | is_gbanned = await is_gbanned_user(user_id)
22 | if is_gbanned:
23 | return
24 | return await gbansdb.insert_one({"user_id": user_id})
25 |
26 |
27 | async def remove_gban_user(user_id: int):
28 | is_gbanned = await is_gbanned_user(user_id)
29 | if not is_gbanned:
30 | return
31 | return await gbansdb.delete_one({"user_id": user_id})
32 |
33 |
34 |
--------------------------------------------------------------------------------
/PyrogramBot/db/notesdb:
--------------------------------------------------------------------------------
1 | from PyrogramBot import db
2 | from typing import Dict, List, Union
3 |
4 |
5 | notesdb = db.notes
6 |
7 |
8 | async def get_notes_count() -> dict:
9 | chats = notesdb.find({"chat_id": {"$lt": 0}})
10 | if not chats:
11 | return {}
12 | chats_count = 0
13 | notes_count = 0
14 | for chat in await chats.to_list(length=1000000000):
15 | notes_name = await get_note_names(chat['chat_id'])
16 | notes_count += len(notes_name)
17 | chats_count += 1
18 | return {
19 | "chats_count": chats_count,
20 | "notes_count": notes_count
21 | }
22 |
23 |
24 | async def _get_notes(chat_id: int) -> Dict[str, int]:
25 | _notes = await notesdb.find_one({"chat_id": chat_id})
26 | if _notes:
27 | _notes = _notes["notes"]
28 | else:
29 | _notes = {}
30 | return _notes
31 |
32 |
33 | async def get_note_names(chat_id: int) -> List[str]:
34 | _notes = []
35 | for note in await _get_notes(chat_id):
36 | _notes.append(note)
37 | return _notes
38 |
39 |
40 | async def get_note(chat_id: int, name: str) -> Union[bool, dict]:
41 | name = name.lower().strip()
42 | _notes = await _get_notes(chat_id)
43 | if name in _notes:
44 | return _notes[name]
45 | else:
46 | return False
47 |
48 |
49 | async def save_note(chat_id: int, name: str, note: dict):
50 | name = name.lower().strip()
51 | _notes = await _get_notes(chat_id)
52 | _notes[name] = note
53 |
54 | await notesdb.update_one(
55 | {"chat_id": chat_id},
56 | {
57 | "$set": {
58 | "notes": _notes
59 | }
60 | },
61 | upsert=True
62 | )
63 |
64 |
65 | async def delete_note(chat_id: int, name: str) -> bool:
66 | notesd = await _get_notes(chat_id)
67 | name = name.lower().strip()
68 | if name in notesd:
69 | del notesd[name]
70 | await notesdb.update_one(
71 | {"chat_id": chat_id},
72 | {
73 | "$set": {
74 | "notes": notesd
75 | }
76 | },
77 | upsert=True
78 | )
79 | return True
80 | return False
--------------------------------------------------------------------------------
/PyrogramBot/db/warnsdb:
--------------------------------------------------------------------------------
1 | from PyrogramBot import db
2 | from typing import Dict, List, Union
3 |
4 |
5 | warnsdb = db.warns
6 |
7 |
8 | async def int_to_alpha(user_id: int) -> str:
9 | alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
10 | text = ""
11 | user_id = str(user_id)
12 | for i in user_id:
13 | text += alphabet[int(i)]
14 | return text
15 |
16 |
17 | async def alpha_to_int(user_id_alphabet: str) -> int:
18 | alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
19 | user_id = ""
20 | for i in user_id_alphabet:
21 | index = alphabet.index(i)
22 | user_id += str(index)
23 | user_id = int(user_id)
24 | return user_id
25 |
26 |
27 | async def get_warns_count() -> dict:
28 | chats = warnsdb.find({"chat_id": {"$lt": 0}})
29 | if not chats:
30 | return {}
31 | chats_count = 0
32 | warns_count = 0
33 | for chat in await chats.to_list(length=100000000):
34 | for user in chat['warns']:
35 | warns_count += chat['warns'][user]['warns']
36 | chats_count += 1
37 | return {
38 | "chats_count": chats_count,
39 | "warns_count": warns_count
40 | }
41 |
42 |
43 | async def get_warns(chat_id: int) -> Dict[str, int]:
44 | warns = await warnsdb.find_one({"chat_id": chat_id})
45 | if warns:
46 | warns = warns['warns']
47 | else:
48 | warns = {}
49 | return warns
50 |
51 |
52 | async def get_warn(chat_id: int, name: str) -> Union[bool, dict]:
53 | name = name.lower().strip()
54 | warns = await get_warns(chat_id)
55 | if name in warns:
56 | return warns[name]
57 |
58 |
59 | async def add_warn(chat_id: int, name: str, warn: dict):
60 | name = name.lower().strip()
61 | warns = await get_warns(chat_id)
62 | warns[name] = warn
63 |
64 | await warnsdb.update_one(
65 | {"chat_id": chat_id},
66 | {
67 | "$set": {
68 | "warns": warns
69 | }
70 | },
71 | upsert=True
72 | )
73 |
74 |
75 | async def remove_warns(chat_id: int, name: str) -> bool:
76 | warnsd = await get_warns(chat_id)
77 | name = name.lower().strip()
78 | if name in warnsd:
79 | del warnsd[name]
80 | await warnsdb.update_one(
81 | {"chat_id": chat_id},
82 | {
83 | "$set": {
84 | "warns": warnsd
85 | }
86 | },
87 | upsert=True
88 | )
89 | return True
90 | return False
91 |
--------------------------------------------------------------------------------
/PyrogramBot/modules/__init__.py:
--------------------------------------------------------------------------------
1 | import glob
2 | import importlib
3 | import sys
4 |
5 | from os.path import dirname, basename, isfile
6 | from PyrogramBot import log
7 |
8 |
9 | def __list_all_modules():
10 | # This generates a list of modules in this
11 | # folder for the * in __main__ to work.
12 | mod_paths = glob.glob(dirname(__file__) + "/*.py")
13 | all_modules = [
14 | basename(f)[:-3]
15 | for f in mod_paths
16 | if isfile(f)
17 | and f.endswith(".py")
18 | and not f.endswith("__init__.py")
19 | and not f.endswith("__main__.py")
20 | ]
21 |
22 |
23 | importlib.import_module("PyrogramBot.modules.__main__")
24 | ALL_MODULES = sorted(__list_all_modules())
25 | log.info("Modules loaded: %s", str(ALL_MODULES))
26 | __all__ = ALL_MODULES + ["ALL_MODULES"]
27 |
--------------------------------------------------------------------------------
/PyrogramBot/modules/__main__.py:
--------------------------------------------------------------------------------
1 | # __main__.py exits the chat
--------------------------------------------------------------------------------
/PyrogramBot/modules/eval.py:
--------------------------------------------------------------------------------
1 | import io
2 | import sys
3 | import traceback
4 | from PyrogramBot import app
5 | from PyrogramBot.config import OWNER_ID
6 | from PyrogramBot.utils.errors import capture_err
7 | from pyrogram import Client, filters
8 |
9 | __MODULE__ = "Eval"
10 | __HELP__ = "/eval [python code] - Evaluate the Given Code"
11 |
12 |
13 | @app.on_message(filters.user(OWNER_ID) & filters.command("eval"))
14 | @capture_err
15 | async def eval(client, message):
16 | status_message = await message.reply_text("Processing ...")
17 | cmd = message.text.split(" ", maxsplit=1)[1]
18 |
19 | reply_to_ = message
20 | if message.reply_to_message:
21 | reply_to_ = message.reply_to_message
22 |
23 | old_stderr = sys.stderr
24 | old_stdout = sys.stdout
25 | redirected_output = sys.stdout = io.StringIO()
26 | redirected_error = sys.stderr = io.StringIO()
27 | stdout, stderr, exc = None, None, None
28 |
29 | try:
30 | await aexec(cmd, client, message)
31 | except Exception:
32 | exc = traceback.format_exc()
33 |
34 | stdout = redirected_output.getvalue()
35 | stderr = redirected_error.getvalue()
36 | sys.stdout = old_stdout
37 | sys.stderr = old_stderr
38 |
39 | evaluation = ""
40 | if exc:
41 | evaluation = exc
42 | elif stderr:
43 | evaluation = stderr
44 | elif stdout:
45 | evaluation = stdout
46 | else:
47 | evaluation = "Success"
48 |
49 | final_output = "EVAL: "
50 | final_output += f"{cmd}
\n\n"
51 | final_output += "OUTPUT:\n"
52 | final_output += f"{evaluation.strip()}
\n"
53 |
54 | if len(final_output) > 4096:
55 | with io.BytesIO(str.encode(final_output)) as out_file:
56 | out_file.name = "eval.text"
57 | await reply_to_.reply_document(
58 | document=out_file, caption=cmd, disable_notification=True
59 | )
60 | else:
61 | await reply_to_.reply_text(final_output)
62 | await status_message.delete()
63 |
64 |
65 | async def aexec(code, client, message):
66 | exec(
67 | "async def __aexec(client, message): "
68 | + "".join(f"\n {l_}" for l_ in code.split("\n"))
69 | )
70 | return await locals()["__aexec"](client, message)
71 |
--------------------------------------------------------------------------------
/PyrogramBot/modules/fun.py:
--------------------------------------------------------------------------------
1 | import pyjokes
2 | from quoters import Quote
3 | from pyrogram import filters
4 | from PyrogramBot import app
5 |
6 | __MODULE__ = "Fun"
7 | __HELP__ = """/quote - Get Quotes\n/joke - Get Jokes\n**Lastly:**\n**Press F** replying someone and check Yourself Okay!"""
8 |
9 | #Using External Modules like 'pyjokes' and 'quoters'
10 |
11 | # ShortCut for Long Codes with Repeating Functions
12 |
13 | jokes = pyjokes.get_joke # You can use this when you have to use the same thing over and over again sometimes, Like For Example, pyjokes.get_joke(language="hi", category="neutral"), pyjokes.get_joke(language="en", category="neutral"), Then Instead of writting 'pyjokes.get_joke' you use your pre-defined function 'jokes' in place of that.
14 |
15 | @app.on_message(filters.command(["joke"]))
16 | async def crackjoke(_, message):
17 | joke = jokes(language="en", category="neutral")
18 | await message.reply_text(joke)
19 |
20 | # Simple way for short codes with single use functions
21 |
22 | @app.on_message(filters.command(["quote"]))
23 | async def quoter(_, message):
24 | quote = Quote.print()
25 | await message.reply_text(quote)
26 |
27 | # Example Of Simple Regex Use From @SupMeta_Bot
28 |
29 | @app.on_message(filters.regex(["(?i)f"]))
30 | async def f(_, message):
31 | if (len(message.text) != 1):
32 | return
33 | if message.reply_to_message:
34 | await message.reply_to_message.reply_text("**Press F** To Pay Respect to This **LeJhand**", parse_mode="markdown")
35 | else:
36 | await message.reply_text("Pay Respect to Whom??, Reply to Someone's Message!")
37 |
38 |
--------------------------------------------------------------------------------
/PyrogramBot/modules/ping.py:
--------------------------------------------------------------------------------
1 | from PyrogramBot import app, bot_start_time
2 | from PyrogramBot.__main__ import BOT_DC_ID
3 | from PyrogramBot.utils.errors import capture_err
4 | from psutil import cpu_percent, virtual_memory, disk_usage, boot_time
5 |
6 | from pyrogram import filters, __version__
7 | from platform import python_version
8 |
9 | import time
10 |
11 | __MODULE__ = "Bot Status"
12 | __HELP__ = "/ping - Check Bot Ping and Uptime\n/status - Check Bot Stats"
13 |
14 | #Formatter
15 |
16 | def get_readable_time(seconds: int) -> str:
17 | count = 0
18 | ping_time = ""
19 | time_list = []
20 | time_suffix_list = ["s", "m", "h", "days"]
21 | while count < 4:
22 | count += 1
23 | if count < 3:
24 | remainder, obtained = divmod(seconds, 60)
25 | else:
26 | remainder, obtained = divmod(seconds, 24)
27 | if seconds == 0 and remainder == 0:
28 | break
29 | time_list.append(int(obtained))
30 | seconds = int(remainder)
31 | for i in range(len(time_list)):
32 | time_list[i] = str(time_list[i]) + time_suffix_list[i]
33 | if len(time_list) == 4:
34 | ping_time += time_list.pop() + ", "
35 | time_list.reverse()
36 | ping_time += ":".join(time_list)
37 | return ping_time
38 |
39 | #Uptime
40 |
41 | bot_uptime = int(time.time() - bot_start_time)
42 |
43 | # Ping
44 |
45 | @app.on_message(filters.command("ping"))
46 | @capture_err
47 | async def ping(_, message):
48 | start_time = time.time()
49 | pong = await message.reply_text("Calculating...")
50 | end_time = time.time()
51 | ping = round((end_time - start_time) * 1000, 3)
52 | await pong.edit_text(
53 | f"**Ping [DC-{BOT_DC_ID}]:** {ping}ms\n\n**Uptime:** {get_readable_time((bot_uptime))}.", parse_mode='markdown')
54 |
55 | # System Info Example
56 |
57 | @app.on_message(filters.command("status"))
58 | @capture_err
59 | async def status(_, message):
60 | ram = virtual_memory().percent
61 | cpu = cpu_percent().percent
62 | disk = disk_usage("/").percent
63 | text = "*>-------< System >-------<*\n\n"
64 | text += f"Uptime: `{get_readable_time((bot_uptime))}`\n"
65 | text += f"**CPU:** `{cpu}%`\n"
66 | text += f"**RAM:** `{ram}%`\n"
67 | text += f"**Disk:** `{disk}%`\n"
68 | text += f"**Python Version:** `{python_version}`\n"
69 | text += "**Library:** `Pyrogram`\n"
70 | text += f"**Pyrogram Version:** `{__version__}`"
71 | await message.reply_text(text, parse_mode="markdown")
--------------------------------------------------------------------------------
/PyrogramBot/modules/start.py:
--------------------------------------------------------------------------------
1 | from PyrogramBot import app
2 | from PyrogramBot.__main__ import BOT_NAME
3 | from PyrogramBot.config import OWNER_ID
4 |
5 | from PyrogramBot.utils.errors import capture_err
6 |
7 | from pyrogram import filters
8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
9 |
10 | __MODULE__ = "Basic"
11 |
12 | __HELP__ = """/start - Start the bot with Inline Buttons
13 | /help - Help Menu
14 | """
15 |
16 | keyboard = InlineKeyboardMarkup(
17 | [
18 | [
19 | InlineKeyboardButton(
20 | text="Example Inline Link Button",
21 | url=f"https://github.com/swatv3nub/PyrogramBot",
22 | ),
23 | InlineKeyboardButton(
24 | text="Example Inline Query Button",
25 | callback_data="example",
26 | )
27 | ]
28 |
29 | #Start
30 |
31 | @app.on_message(filters.command("start"))
32 | @capture_err
33 | async def start(_, message):
34 | start_text=f"Hello {message.from_user.mention}, I am {BOT_NAME}\n\nMy Onwer is [{OWNER_ID}](tg://user?id={OWNER_ID})"
35 | await message.reply_text(start_text, reply_markup=keyboard, parse_mode="markdown")
36 |
37 |
38 | @app.on_callback_query(filters.regex("example"))
39 | async def example(_, CallBackQuery):
40 | await app.answer_callback_query(CallbackQuery.id, "Surprise!", show_alert=True)
41 |
42 |
43 | #Help { in __main__.py }
--------------------------------------------------------------------------------
/PyrogramBot/utils/errors.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import traceback
3 | from functools import wraps
4 | from PyrogramBot import app, LOG_CHANNEL
5 |
6 |
7 | def split_limits(text):
8 | if len(text) < 2048:
9 | return [text]
10 |
11 | lines = text.splitlines(True)
12 | small_msg = ''
13 | result = []
14 | for line in lines:
15 | if len(small_msg) + len(line) < 2048:
16 | small_msg += line
17 | else:
18 | result.append(small_msg)
19 | small_msg = line
20 | else:
21 | result.append(small_msg)
22 |
23 | return result
24 |
25 |
26 | def capture_err(func):
27 | @wraps(func)
28 | async def caperr(client, message, *args, **kwargs):
29 | try:
30 | return await func(client, message, *args, **kwargs)
31 | except Exception as err:
32 | exc_type, exc_obj, exc_tb = sys.exc_info()
33 | errors = traceback.format_exception(
34 | etype=exc_type, value=exc_obj, tb=exc_tb,
35 | )
36 | error_feedback = split_limits(
37 | '**Logged Error**\n\n**Command User:** `{}` | **Chat:** `{}`\n\nCommand Used:```{}```\n\n**Incoming Error**```{}```\n'.format(
38 | 0 if not message.from_user else message.from_user.id,
39 | 0 if not message.chat else message.chat.id,
40 | message.text or message.caption,
41 | ''.join(errors),
42 | ),
43 | )
44 | for x in error_feedback:
45 | await app.send_message(
46 | LOG_CHANNEL,
47 | x
48 | )
49 | raise err
50 | return caperr
51 |
--------------------------------------------------------------------------------
/PyrogramBot/utils/misc.py:
--------------------------------------------------------------------------------
1 | from math import ceil
2 | from pyrogram.types import InlineKeyboardButton
3 | from PyrogramBot import LOAD_MODULES, NOLOAD_MODULES
4 |
5 |
6 | class EqInlineKeyboardButton(InlineKeyboardButton):
7 | def __eq__(self, other):
8 | return self.text == other.text
9 |
10 | def __lt__(self, other):
11 | return self.text < other.text
12 |
13 | def __gt__(self, other):
14 | return self.text > other.text
15 |
16 |
17 | def count_modules(page_n, module_dict, prefix, chat=None):
18 | if not chat:
19 | modules = sorted(
20 | [
21 | EqInlineKeyboardButton(
22 | x.__MODULE__,
23 | callback_data="{}_module({})".format(
24 | prefix, x.__MODULE__.lower()),
25 | )
26 | for x in module_dict.values()
27 | ]
28 | )
29 | else:
30 | modules = sorted(
31 | [
32 | EqInlineKeyboardButton(
33 | x.__MODULE__,
34 | callback_data="{}_module({},{})".format(
35 | prefix, chat, x.__MODULE__.lower()
36 | ),
37 | )
38 | for x in module_dict.values()
39 | ]
40 | )
41 |
42 | pairs = list(zip(modules[::3], modules[1::3], modules[2::3]))
43 | i = 0
44 | for m in pairs:
45 | for _ in m:
46 | i += 1
47 | if len(modules) - i == 1:
48 | pairs.append((modules[-1],))
49 | elif len(modules) - i == 2:
50 | pairs.append(
51 | (
52 | modules[-2],
53 | modules[-1],
54 | )
55 | )
56 |
57 | max_num_pages = ceil(len(pairs) / 7)
58 | modulo_page = page_n % max_num_pages
59 |
60 | # can only have a certain amount of buttons side by side
61 | if len(pairs) > 7:
62 | pairs = pairs[modulo_page * 7: 7 * (modulo_page + 1)] + [
63 | (
64 | EqInlineKeyboardButton(
65 | "<",
66 | callback_data="{}_prev({})".format(
67 | prefix, modulo_page
68 | ),
69 | ),
70 | EqInlineKeyboardButton(
71 | ">",
72 | callback_data="{}_next({})".format(
73 | prefix, modulo_page
74 | ),
75 | ),
76 | )
77 | ]
78 |
79 | return pairs
80 |
81 |
82 | def is_module_loaded(name):
83 | return (not LOAD_MODULES or name in LOAD_MODULES) and name not in NOLOAD_MODULES
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PyrogramBot
2 |
3 | [](https://www.python.org/)
4 | [](https://GitHub.com/swatv3nub/)
5 |
6 |
7 | 
8 | 
9 | 
10 | 
11 | 
12 | 
13 | 
14 | 
15 | 
16 |
17 | Simple Base for Users Who wants to make their own Telegram Bots in **[Pyrogram](http://github.com/Pyrogram/Pyrogram)** with or without **[Mongo Database](https://mongodb.com)**
18 |
19 | ## How to add modules?
20 |
21 | - Fork and add your modules in **[PyrogramBot/modules](https://github.com/swatv3nub/PyrogramBot/blob/Alpha/PyrogramBot/modules)**
22 | - Add Required ENV Variables in **[app.json](https://github.com/swatv3nub/PyrogramBot/blob/Alpha/app.json)** & in **[config.py](https://github.com/swatv3nub/PyrogramBot/blob/Alpha/PyrogramBot/config.py)**
23 | - Add required external requirements in **[requirements.txt](https://github.com/swatv3nub/PyrogramBot/blob/Alpha/requirements.txt)**
24 |
25 | ## Hosting
26 |
27 | ### Heroku
28 |
29 | - Heroku Deploy is Very Simple, Just Click the Button Below
30 |
31 | [](https://heroku.com/deploy?template=https://github.com/swatv3nub/PyrogramBot)
32 |
33 | ### Local Deploy
34 |
35 | - `git clone https://github.com/swatv3nub/PyrogramBot`
36 | - `cd PyrogramBot`
37 | - `pip3 install -r requirements.txt`
38 | - Edit The `config.py` as per the instruction given there.
39 | - `python3 -m PyrogramBot`
40 |
41 | ## Report Bugs
42 |
43 | Report Bugs in [@PythonDevsChat](https://t.me/PythonDevsChat)
44 |
45 | Do Fork And Star The Repository If You Liked It.
46 |
47 | ## Credits
48 | - [Dan Tès](https://telegram.dog/haskell) for His [Pyrogram Library](https://github.com/Pyrogram/Pyrogram)
49 | - MaskedVirus - [Telegram](https://t.me/MaskedVirus) | [GitHub](https://github.com/swatv3nub)
50 | - TheHamkerCat - [Telegram](https://t.me/TheHamkerCat) | [GitHub](https://github.com/TheHamkerCat)
51 |
52 |
53 | ## Powered By
54 |
55 | [](https://t.me/PythonDevs)
56 |
57 | [](https://t.me/TheCodents)
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PyrogramBot",
3 | "description": "Bot written in Python using the Pyrogram Library - Sample",
4 | "keywords": [
5 | "telegram",
6 | "python",
7 | "pyrogram"
8 | ],
9 | "repository": "https://github.com/swatv3nub/PyrogramBot",
10 | "success_url": "https://telegram.dog/ProjectHackfreaks",
11 | "website": "https://github.com/swatv3nub",
12 | "env": {
13 | "ENV": {
14 | "description": "Setting this to ANYTHING will enable webhooks when in env mode",
15 | "value": "ANYTHING"
16 | },
17 | "API_ID": {
18 | "description": "Get this value from https://my.telegram.org",
19 | "required": true
20 | },
21 | "API_HASH": {
22 | "description": "Get this value from https://my.telegram.org",
23 | "required": true
24 | },
25 | "BOT_TOKEN": {
26 | "description": "Get this value from @BotFather"
27 | "required": true
28 | },
29 | "OWNER_ID": {
30 | "description": "Your ID",
31 | "required": true
32 | }
33 | },
34 | "buildpacks": [
35 | {
36 | "url": "heroku/python"
37 | }],
38 | "formation": {
39 | "worker": {
40 | "quantity": 1,
41 | "size": "free"
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/heroku.yml.sample:
--------------------------------------------------------------------------------
1 | build:
2 | docker:
3 | worker: Dockerfile
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | TgCrypto
2 | aiohttp
3 | pyrogram
4 | python-dateutil
5 | pyjokes
6 | quoters
7 | psutil
8 | pykeyboard
9 | #motor
10 | dnspython
11 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.9.1
2 |
--------------------------------------------------------------------------------