├── Dockerfile ├── Procfile ├── README.md ├── annabelle.py ├── annabelle ├── __init__.py ├── database │ ├── gban_db.py │ ├── gmute_db.py │ ├── pmpermit_db.py │ └── users_db.py ├── helper_funcs │ ├── admin_check.py │ └── strings.py └── modules │ ├── afk.py │ ├── alive.py │ ├── autobio.py │ ├── autodp.py │ ├── block.py │ ├── blockusername.py │ ├── calculator.py │ ├── checks.py │ ├── clone.py │ ├── covid.py │ ├── create.py │ ├── forward_all.py │ ├── gban.py │ ├── github.py │ ├── help.py │ ├── helpers │ ├── afk_handler.py │ └── mirror_func.py │ ├── helpmenu │ └── help_menu.py │ ├── inline.py │ ├── leave.py │ ├── mirror.py │ ├── pin.py │ ├── ping.py │ ├── pmpermit.py │ ├── purge.py │ ├── qoutly.py │ ├── screenshot.py │ ├── sendmod.py │ ├── set.py │ ├── spam.py │ ├── tagall.py │ ├── thumbnail.py │ ├── typewritter.py │ └── wiki.py ├── app.json ├── bot.py ├── config.py ├── docker-compose.yml ├── mainbot └── start.py ├── requirements.txt ├── runtime.txt └── start /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9.1 2 | WORKDIR /app 3 | COPY requirements.txt requirements.txt 4 | RUN pip3 install -r requirements.txt 5 | COPY . . 6 | CMD python3 bot.py 7 | CMD python3 annabelle.py 8 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 Annabelle.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Annabelle

2 | 3 |
4 |

TELEGRAM USERBOT


5 | 6 | 7 | Telegram's lightest userbot with many plugins and tools. 8 | Written in python based on pyrogram 9 | 10 |

Annabelle is telegram's lightest, fastest and most secure userbot.
Annabelle is filled with
11 | • Admin tools
12 | • Funs
13 | • Private tools

14 |

disclaimer

15 | 16 | ```Copyright @AnnabelleTG 17 | This repository and its files belongs to AnnabelleTG. Usage of any files in this repo will be prosecuted. 18 | Only owners have the permission to kang the repo 19 | If you see a cloned repo(excluding forks) of our repo, please report that to us 20 | ``` 21 | 22 |

Deployment

23 | Help for deploying the userbot
24 |
25 | 26 | API_ID: API_ID from website or bot
27 | API_HASH: API_HASH from site or bot
28 | SESSION_STRING: pyrogram session string from bot or repos
29 | DATABASE_NAME: Your MongoDB database name
30 | DATABASE_URL: Your MONGODB url
31 | HANDLER: The command prefix. eg . ,
32 | SUDO_USERS: ID of users who can use your bot's certain other than you
33 | MY_ID: Your telegram ID
34 | 35 |

Configuration

36 | There are two types of clients in our repo. Bot and userbot.
37 | For importing client use this:
38 | 39 | ``` 40 | from annabelle import Annabelle 41 | #for importing userbot 42 | 43 | from bot import mainbot 44 | #for importing bot 45 | ``` 46 |

Thanks and Credits

47 | Thanks to Jisin for his help
48 | Thanks to Jithumon
49 | Thanks to the whole Dora support team
50 | Thanks to our buddy Joel boban and Blesson
51 | Thanks to Userge for being our inspiration
52 | -------------------------------------------------------------------------------- /annabelle.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, __version__ 2 | from config import * 3 | import logging 4 | 5 | art = """ 6 | 7 | _____ ___. .__ .__ 8 | / _ \ ____ ____ _____ \_ |__ ____ | | | | ____ 9 | / /_\ \ / \ / \\__ \ | __ \_/ __ \| | | | _/ __ \ 10 | / | \ | \ | \/ __ \| \_\ \ ___/| |_| |_\ ___/ 11 | \____|__ /___| /___| (____ /___ /\___ >____/____/\___ > 12 | \/ \/ \/ \/ \/ \/ \/ 13 | 14 | 15 | """ 16 | 17 | class Annabelle(Client): 18 | 19 | def __init__(self): 20 | super().__init__( 21 | SESSION_STRING, 22 | api_id=API_ID, 23 | api_hash=API_HASH, 24 | plugins={"root": "annabelle/modules"}, 25 | ) 26 | 27 | async def start(self): 28 | await super().start() 29 | print(art) 30 | logging.info(f"Anabelle with for Pyrogram v{__version__} (Layer {layer}) started") 31 | 32 | async def stop(self, *args): 33 | await super().stop() 34 | logging.info("Anabelle stopped!") 35 | -------------------------------------------------------------------------------- /annabelle/__init__.py: -------------------------------------------------------------------------------- 1 | from os import path, mkdir 2 | from sys import stdout 3 | from datetime import datetime 4 | from logging import INFO, WARNING, FileHandler, StreamHandler, basicConfig, getLogger 5 | from annabelle import Annabelle 6 | 7 | LOG_DATETIME = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") 8 | LOGDIR = f"{__name__}/logs" 9 | 10 | if not path.isdir(LOGDIR): 11 | mkdir(LOGDIR) 12 | 13 | LOGFILE = f"{LOGDIR}/{__name__}_{LOG_DATETIME}_log.txt" 14 | 15 | file_handler = FileHandler(filename=LOGFILE) 16 | stdout_handler = StreamHandler(stdout) 17 | 18 | basicConfig( 19 | format="%(asctime)s - [Annabelle] - %(levelname)s - %(message)s", 20 | level=INFO, 21 | handlers=[file_handler, stdout_handler], 22 | ) 23 | 24 | getLogger("pyrogram").setLevel(WARNING) 25 | logger = getLogger(__name__) 26 | 27 | 28 | 29 | app = Annabelle() 30 | app.run() 31 | -------------------------------------------------------------------------------- /annabelle/database/gban_db.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from pymongo import MongoClient 3 | 4 | from config import DATABASE_NAME, DATABASE_URL 5 | from annabelle.database.gmutes_db import check_gmute, un_gmute 6 | 7 | client = MongoClient(DATABASE_URL) 8 | mydb = client[DATABASE_NAME] 9 | gban_col = mydb['GBANS'] 10 | 11 | def add_gban(id): 12 | checks = check_gmute(id) 13 | if checks is True: 14 | un_gmute(id) 15 | x = gban_col.find_one(id) 16 | if x: 17 | return 18 | else: 19 | return gban_col.insert_one({'_id' : id, 'reason' : reason}) 20 | 21 | def un_gban(id): 22 | x = gban_col.find_one(id) 23 | if x: 24 | return gban_col.delete_one(id) 25 | else: 26 | return False 27 | 28 | def check_gban(id): 29 | x = gban_col.find_one(id) 30 | if x: 31 | return reason 32 | else: 33 | return False 34 | 35 | -------------------------------------------------------------------------------- /annabelle/database/gmute_db.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from pymongo import MongoClient 3 | 4 | from config import DATABASE_URL as DB_URL 5 | from config import DATABASE_NAME as DB_NAME 6 | 7 | import logging 8 | logging = logging.getLogger(__name__) 9 | 10 | mydb = MongoClient(DB_NAME) 11 | gmute_col = mydb['GMUTE'] 12 | 13 | def add_gmute(id, reason): 14 | x = gmute_col.find_one(id) 15 | if x: 16 | return 17 | else: 18 | return gmute_col.insert_one({'_id" : id, 'reason' : reason}) 19 | 20 | def check_gmute(id): 21 | x = gmute_col.find_one(id) 22 | if x: 23 | return reason 24 | else: 25 | return False 26 | 27 | def ungmute(id): 28 | x = gban_col.find_one(id) 29 | if x: 30 | return gban_col.delete_one({'_id : id}) 31 | else: 32 | return False 33 | -------------------------------------------------------------------------------- /annabelle/database/pmpermit_db.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from pymongo import MongoClient 3 | from config import ( 4 | DATABASE_NAME, 5 | DATABASE_URL 6 | ) 7 | 8 | client = MongoClient(DATABASE_URL) 9 | mydb = client[DATABASE_NAME] 10 | pm_col = mydb['PM PERMITS'] 11 | 12 | def add_permit(id): 13 | x = pm_col.find_one(id) # to avoid duplicate ids 14 | if x: 15 | return False 16 | else: 17 | return pm_col.insert_one({'_id' : id}) 18 | 19 | def check_permit(id): 20 | x = pm_col.find_one(id) 21 | if x: 22 | return True 23 | else: 24 | return False 25 | 26 | def del_permit(id): 27 | x = check_permit(id) 28 | if x is True: 29 | return pm_col.delete_one({'_id' : id}) 30 | else: 31 | return False 32 | -------------------------------------------------------------------------------- /annabelle/database/users_db.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from pymongo import MongoClient 3 | 4 | from config import ( 5 | DATABASE_NAME, 6 | DATABASE_URL 7 | ) 8 | 9 | client = MongoClient(database_url) 10 | mydb = client['USER BOT'] 11 | user_col = mydb['USERS'] 12 | chat_col = mydb['CHATS'] 13 | 14 | def add_user(id): 15 | x = user_col.find_one(id) 16 | if x: 17 | return 18 | else: 19 | return user_col.insert_one({'_id' : id}) 20 | 21 | def check_user(id): 22 | x = user_col.find_one(id) 23 | if x: 24 | return True 25 | else: 26 | return False 27 | 28 | 29 | -------------------------------------------------------------------------------- /annabelle/helper_funcs/admin_check.py: -------------------------------------------------------------------------------- 1 | from pyrogram.types import Message 2 | 3 | 4 | async def admin_check(message: Message) -> bool: 5 | if not message.from_user: 6 | return False 7 | 8 | if message.chat.type not in ["supergroup", "channel"]: 9 | return False 10 | 11 | if message.from_user.id in [ 12 | 777000, 13 | 1087968824 14 | ]: 15 | return True 16 | 17 | client = message._client 18 | chat_id = message.chat.id 19 | user_id = message.from_user.id 20 | 21 | check_status = await client.get_chat_member( 22 | chat_id=chat_id, 23 | user_id=user_id 24 | ) 25 | admin_strings = [ 26 | "creator", 27 | "administrator" 28 | ] 29 | if check_status.status not in admin_strings: 30 | return False 31 | else: 32 | return True 33 | 34 | -------------------------------------------------------------------------------- /annabelle/helper_funcs/strings.py: -------------------------------------------------------------------------------- 1 | WORK_TXT = ''' 2 | 📔📚 📚 3 | 📓📚📖 😫 📚📚📓 4 | 📕📚📚 📝 📗💻📘 5 | 📖📖📖📖📖📖📖📖 6 | **Doing my work** 7 | ✏️📝✏️📝✏️📝✏️📝 8 | ''' 9 | GBAN_TXT = ''' 10 | **GBAN** 11 | 12 | {} has been globally banned! 13 | 14 | **Reason ** 15 | ''' 16 | MORNING_TXT = ''' 17 | 18 | G🌷o🍃o🌷D 19 | M🍃o🌷r🍃N🌷i🍃N🌷g 20 | 21 | No matter how good or 22 | bad your life is, 23 | wake up each morning 24 | and be thankful. 25 | You still have a new day. 26 | 27 | Good morning 28 | 29 | 🌞 30 | 31 | ╱◥████◣ 32 | │田│▓ ∩│◥███◣ 33 | ╱◥◣ ◥████◣田∩田│ 34 | │╱◥█◣║∩∩∩ 田∩田│ 35 | ║◥███◣∩田∩ 田∩田│ 36 | │∩│ ▓ ║∩田│║▓田▓ 37 | 🌹🌷🌹🌷🌹🍃🌷🌹🌷🌹 38 | ''' 39 | 40 | COVID_TXT = ( 41 | "Always wear mask", 42 | "**SMS:** sanitize, mask, social-distancing", 43 | "Wash your hands with soap for atleast 20sec" 44 | ) 45 | 46 | ALIVE_TXT = ''' 47 | **ANNABELLE USERBOT** 48 | 49 | **{0}Language: [Python3](www.python.org)** 50 | **{0}Server: [Heroku](www.heroku.com)** 51 | **{0}Framework: Pyrogram asyncio** 52 | **{0}Database: [Mongodb](www.mongodb.com) 53 | **{0}Developers: [Team XD Botz](t.me/XD_Botz)** 54 | **{0}Repo: [Click Here](github.com/vaishnavofficial/annabelle)** 55 | ''' 56 | -------------------------------------------------------------------------------- /annabelle/modules/afk.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 4 | # Copyright Here 5 | 6 | 7 | """ 8 | import asyncio 9 | 10 | from config import HANDLER 11 | from annabelle.modules.helpers.afk_helpers import afk_handler 12 | from annabelle.modules.helpmenu.help_menu import modules_help 13 | 14 | from datetime import datetime 15 | from pyrogram import Client, filters 16 | from pyrogram.handlers import MessageHandler 17 | 18 | 19 | @Client.on_message(filters.command("afk", HANDLER) & filters.me) 20 | async def afk(client: Client, message): 21 | global start, end, handler, reason 22 | start = datetime.now().replace(microsecond=0) 23 | handler = await client.add_handler( 24 | MessageHandler(afk_handler, (filters.private & ~filters.me)) 25 | ) 26 | text = message.text.split(None, 1) 27 | if len(text) >= 2: 28 | reason = text[1] 29 | await message.edit(f"I'm going afk\n**reason**: `{reason}`") 30 | else: 31 | reason = None 32 | await message.edit("I'm going afk") 33 | 34 | 35 | @Client.on_message(filters.command("unafk", prefixes=f"{HANDLER}") & filters.me) 36 | async def unafk(client: Client, message): 37 | try: 38 | global start, end 39 | end = datetime.datetime.now().replace(microsecond=0) 40 | afk_dur = end - start 41 | await message.edit(f"I'm not AFK any more. I was AFK {afk_dur}") 42 | client.remove_handler(*handler) 43 | except NameError: 44 | await message.edit("You aren't AFK Now") 45 | await asyncio.sleep(3) 46 | await message.delete() 47 | 48 | modules_help.append( 49 | {"afk": [{"afk [reason]": "Go to afk"}, {"unafk": "Get out of AFK"}]} 50 | ) 51 | -------------------------------------------------------------------------------- /annabelle/modules/alive.py: -------------------------------------------------------------------------------- 1 | from config import MY_ID 2 | from annabelle.helper_funcs.strings import ALIVE_TXT 3 | from config ALIVE_EMOJI 4 | from annabelle import Annabelle 5 | from pyrogram import filters as vrn 6 | 7 | DEFAULT_IMG = "https://telegra.ph/file/0cf9d9cea0eebd03f6c1e.jpg" 8 | @Annabelle.on_message(vrn.command('alive', HANDLER)) 9 | async def alive(Annabelle, message): 10 | if message.from_user.id == MY_ID: 11 | await message.reply_photo(photo=DEFAULT_IMG, 12 | caption=ALIVE_TXT.format(ALIVE_EMOJI) 13 | ) 14 | -------------------------------------------------------------------------------- /annabelle/modules/autobio.py: -------------------------------------------------------------------------------- 1 | import pytz 2 | import asyncio 3 | import datetime 4 | from annabelle import Annabelle 5 | from pyrogram import filters as vrn 6 | from config import MY_ID, HANDLER 7 | from pyrogram.types.messages_and_media import Message 8 | 9 | 10 | 11 | @Annabelle.on_message(vrn.command("autobio", HANDLER)) 12 | async def autobio(bot:Annabelle, msg:Message) : 13 | value = msg.text.split(None, 1) 14 | args = value[1].lower() 15 | if args == "true" : 16 | await msg.edit_text(text="**__Plugin Enabled__** : `autobio`") 17 | while value is "true" : 18 | await asyncio.sleep(60) 19 | hour = datetime.datetime.now(pytz.timezone("Asia/Kolkata")).hour 20 | minute = datetime.datetime.now(pytz.timezone("Asia/Kolkata")).minute 21 | await bot.update_profile(bio=f"H : {hour} , M : {minute}") 22 | 23 | elif args == "false" : 24 | await msg.edit_text(text="**__Plugin Disabled__** : `autobio`") 25 | 26 | else : 27 | await msg.edit_text(text="**__Please input a boolean as a parameter !!__**") 28 | -------------------------------------------------------------------------------- /annabelle/modules/autodp.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from annabelle import Annabelle 3 | from pyrogram import filters as vrn 4 | from config import MY_ID, HANDLER, CHANNEL_ID 5 | from pyrogram.types.messages_and_media import Message 6 | 7 | 8 | @Annabelle.on_message(filters.command("autodp", HANDLER)) 9 | async def autodp(bot:Annabelle, msg:Message) : 10 | chat_id = CHANNEL_ID 11 | if msg.from_user.id == MY_ID : 12 | try : 13 | value = msg.text.split(" ")[1].lower() 14 | except : 15 | await msg.edit_text(text="**__Please Enter a value__**") 16 | if value == "true" : 17 | for i in await bot.get_history(chat_id) : 18 | await msg.edit_text(text="**__Plugin Enabled__** : `autodp`") 19 | profile_pic = await bot.download_media(message=i.photo.file_id) 20 | asyncio.sleep(4000) 21 | await bot.set_profile_photo(photo=profile_pic) 22 | elif value == "false" : 23 | await msg.edit_text(text="**__Plugin Disabled__** : `autodp`") 24 | else : 25 | await msg.edit_text(text="**__Please enter a boolean instead of blah blah blah__**") 26 | -------------------------------------------------------------------------------- /annabelle/modules/block.py: -------------------------------------------------------------------------------- 1 | # https://github.com/vaishnavofficial/Annabelle 2 | from annabelle import Annabelle 3 | from pyrogram import filters as vrn 4 | from config import HANDLER 5 | 6 | @Annabelle.on_message(vrn.command('block', HANDLER)) 7 | async def block(bot, message): 8 | if message.from_user.id == MY_ID: 9 | if message.reply_to_message: 10 | ban_id = message.reply_to_message.from_user.id 11 | await bot.block_user(ban_id) 12 | await message.edit("`Haa! Blocked that user`") 13 | else: 14 | args = message.text.split(None, 1) 15 | ban_name = args[1] 16 | await bot.block_user(ban_name) 17 | await message.edit("Blocked that user") 18 | 19 | @Annabelle.on_message(vrn.command('unblock', HANDLER)) 20 | async def unblock(bot, message): 21 | try: 22 | if message.from_user.id == MY_ID: 23 | if message.reply_to_message: 24 | ban_id = message.reply_to_message.from_user.id 25 | await bot.unblock_user(ban_id) 26 | await message.edit("`Haa! Unblocked that user`") 27 | else: 28 | args = message.text.split(None, 1) 29 | ban_name = args[1] 30 | await bot.unblock_user(ban_name) 31 | await message.edit("Unblocked that user") 32 | except Exception as e: 33 | await message.edit("Something went wrong! Check app logs") 34 | print(e) 35 | -------------------------------------------------------------------------------- /annabelle/modules/blockusername.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import Message 3 | from config import HANDLER 4 | from annabelle.modules.helpmenu.help_menu import modules_help 5 | 6 | 7 | @Client.on_message(filters.command(["block"], prefixes=f"{HANDLER}") & filters.me) 8 | async def block_True(client: Client, message: Message): 9 | try: 10 | user_id = message.command[1] 11 | await client.block_user(user_id) 12 | await message.edit( 13 | f"😡 The user is now blacklisted!" 14 | ) 15 | except Exception as e: 16 | await message.edit(f"😨 Ooops: {e}") 17 | 18 | 19 | @Client.on_message(filters.command(["unblock"], prefixes=f"{HANDLER}") & filters.me) 20 | async def unblock(client: Client, message: Message): 21 | try: 22 | user_id = message.command[1] 23 | await client.unblock_user(user_id) 24 | await message.edit( 25 | f"☺️ User removed from the blacklist!" 26 | ) 27 | except Exception as e: 28 | await message.edit(f"😰 Oops: {e}") 29 | 30 | 31 | modules_help.append( 32 | { 33 | "blacklist": [ 34 | {"block [user_id]*": "Block user"}, 35 | {"unblock [user_id]*": "Unblock user"}, 36 | ] 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /annabelle/modules/calculator.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 4 | # Copyright ©️ 5 | 6 | 7 | 8 | """ 9 | 10 | import asyncio 11 | from pyrogram import Client, filters 12 | from pyrogram.types import Message 13 | from config import HANDLER 14 | from annabelle.modules.helpmenu.help_menu import modules_help 15 | 16 | 17 | @Client.on_message(filters.command("calc", prefixes=f"{HANDLER}") & filters.me) 18 | async def calc(client: Client, message: Message): 19 | if len(message.command) <= 1: 20 | return 21 | args = " ".join(message.command[1:]) 22 | try: 23 | result = str(eval(args)) 24 | 25 | if len(result) > 4096: 26 | i = 0 27 | for x in range(0, len(result), 4096): 28 | if i == 0: 29 | await message.edit( 30 | f"{args}={result[x:x + 4000]}", 31 | parse_mode="HTML", 32 | ) 33 | else: 34 | await message.reply( 35 | f"{result[x:x + 4096]}", parse_mode="HTML" 36 | ) 37 | i += 1 38 | await asyncio.sleep(0.18) 39 | else: 40 | await message.edit( 41 | f"{args}={result}", parse_mode="HTML" 42 | ) 43 | except Exception as e: 44 | await message.edit(f"{args}=={e}", parse_mode="HTML") 45 | 46 | 47 | modules_help.append( 48 | { 49 | "calculator": [ 50 | { 51 | "calc [expression]*": "Solve a math problem\n+ – addition\n– – subtraction\n* – multiplication\n/ – division\n** – degree" 52 | } 53 | ] 54 | } 55 | ) 56 | -------------------------------------------------------------------------------- /annabelle/modules/checks.py: -------------------------------------------------------------------------------- 1 | from annabelle import Annabelle 2 | from annabelle.database.gbans import check_gban 3 | from annabelle.database.gmutes import check_gmute 4 | from config import MY_ID 5 | from pyrogram.types import ChatPermissions 6 | 7 | @Annabelle.on_message(filters.new_chat_member & filters.group) 8 | async def ayoo(Annabelle, message): 9 | id = message.from_user.id 10 | member = await Annabelle.get_chat_member(message.chat.id, MY_ID) 11 | x = check_gban(id) 12 | if x is not False: 13 | try: 14 | await bot.kick_chat_member(message.chat.id, id) 15 | await message.reply(f"`Recently joined user is globally banned! I have kicked him`\nreason:`{x}`") 16 | except: 17 | await message.reply(f"`Warning! Recently joined user is globally banned!`\nreason: `{x}`") 18 | else: 19 | id = message.from_user.id 20 | x = check_gmute(id) 21 | if x is not False: 22 | try: 23 | await Annabelle.restrict_chat_member(message.chat.id, id, ChatPermissions()) 24 | await message.reply(f"`Recently joined user is globally muted!` I have muted him`\nreason: `{x}`") 25 | except: 26 | await message.reply(f"`WARNING\n Recently joined user is globally muted for reason: {x}`") 27 | 28 | 29 | # hope it works 30 | -------------------------------------------------------------------------------- /annabelle/modules/clone.py: -------------------------------------------------------------------------------- 1 | from annabelle import Annabelle 2 | from pyrogram import Client 3 | from config import MY_ID, HANDLER 4 | from pyrogram import filters as vrn 5 | from pyrogram.types.messages_and_media import Message 6 | 7 | 8 | 9 | @Annabelle.on_message(filters.command("clone", HANDLER) & filters.me) 10 | async def clone(bot:Client, msg:Message) : 11 | if msg.from_user.id == MY_ID : 12 | if msg.chat.type == "group" or msg.chat.type == "supergroup" : 13 | try : 14 | user = msg.reply_to_message.from_user 15 | 16 | try : 17 | pic = await bot.download_media(message=user.photo.big_file_id) 18 | await bot.set_profile_photo(photo=pic) 19 | except : 20 | print("No profile photo !") 21 | 22 | firstname = user.first_name 23 | 24 | if user.last_name : 25 | lastname = user.last_name 26 | else : 27 | lastname = "" 28 | 29 | await bot.update_profile(first_name=firstname, last_name=lastname) 30 | await msg.edit_text(text="`Cloned Successfully !`") 31 | 32 | except : 33 | await msg.edit_text(text="`Couldnt clone !!`") 34 | 35 | 36 | elif msg.chat.type == "private" : 37 | try : 38 | 39 | try : 40 | user = msg.chat 41 | except : 42 | user = msg.reply_to_message.from_user 43 | 44 | try : 45 | pic = user.photo.big_file_id 46 | await bot.set_profile_photo(photo=pic) 47 | except : 48 | pic = "" 49 | 50 | firstname = user.first_name 51 | 52 | if user.last_name : 53 | lastname = user.last_name 54 | else : 55 | lastname = "" 56 | 57 | await bot.update_profile(first_name=firstname, last_name=lastname) 58 | 59 | await msg.edit_text(text="**Cloned Successfully !**") 60 | except : 61 | await msg.edit_text(text="**Couldnt Clone !**") 62 | else : 63 | await msg.edit_text(text=**Couldnt Clone !**") 64 | 65 | -------------------------------------------------------------------------------- /annabelle/modules/covid.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from requests.utils import requote_uri 4 | from pyrogram import filters as vrn 5 | from config import HANDLER 6 | from annabelle import Annabelle 7 | 8 | API = "https://api.sumanjay.cf/covid/?country=" 9 | 10 | @Annabelle.on_message(filters.command("covid", HANDLER)) 11 | async def reply_info(client, message): 12 | query = message.text.split(None, 1)[1] 13 | reply_markup = BUTTONS 14 | await message.edit( 15 | text=covid_info(query), 16 | disable_web_page_preview=True, 17 | quote=True, 18 | ) 19 | 20 | 21 | def covid_info(country_name): 22 | try: 23 | r = requests.get(API + requote_uri(country_name.lower())) 24 | info = r.json() 25 | country = info['country'].capitalize() 26 | active = info['active'] 27 | confirmed = info['confirmed'] 28 | deaths = info['deaths'] 29 | info_id = info['id'] 30 | last_update = info['last_update'] 31 | latitude = info['latitude'] 32 | longitude = info['longitude'] 33 | recovered = info['recovered'] 34 | covid_info = f""" 35 | **♻️ Covid 19 Information** 36 | **🌐 Country :** `{country}` 37 | **🎭 Actived :** `{active}` 38 | **✅ Confirmed :** `{confirmed}` 39 | **⚰️ Deaths :** `{deaths}` 40 | **🆔 ID :** `{info_id}` 41 | **🚨 Last Update :** `{last_update}` 42 | **⚓ Latitude :** `{latitude}` 43 | **🗼 Longitude :** `{longitude}` 44 | **🎙️ Recovered :** `{recovered}` 45 | """ 46 | return covid_info 47 | except Exception as error: 48 | return error 49 | 50 | 51 | @Annabelle.on_message(vrn.command("corona", HANDELR)) 52 | async def covid(Annabelle, message): 53 | query = message.text.split(None, 1)[1] 54 | reply_markup = BUTTONS 55 | await message.edit( 56 | text=covid_info(query), 57 | disable_web_page_preview=True, 58 | quote=True 59 | ) 60 | -------------------------------------------------------------------------------- /annabelle/modules/create.py: -------------------------------------------------------------------------------- 1 | from annabelle import Annabelle 2 | from pyrogram import filters as vrn 3 | 4 | @Annabelle.on_message(vrn.command('group', HANDLER)) 5 | async def create_gr(Annabelle, message): 6 | if message.from_user.id == MY_ID: 7 | if message.reply_to_message: 8 | try: 9 | add_id = message.reply_to_message.from_user.id 10 | args = message.text.split(None, 1) 11 | title = args[1] 12 | await Annabelle.create_group(title, add_id) 13 | await message.edit(f"`successfully made a new group {title}`") 14 | except: 15 | await message.edit("`That user cant be added to a group`") 16 | 17 | @Annabelle.on_message(vrn.command('channel', HANDLER)) 18 | async def create_ch(Annabelle, message): 19 | if message.from_user.id == MY_ID: 20 | args = message.text.split(None, 1) 21 | title = args[1] 22 | await Annabelle.create_channel(title, 'made with annabelle userbot') 23 | await message.edit(f"`successfully made a new channel {title}`") 24 | -------------------------------------------------------------------------------- /annabelle/modules/forward_all.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.errors import FloodWait 4 | from pyrogram.types import Message 5 | from config import HANDLER 6 | from annabelle.modules.helpmenu.help_menu import modules_help 7 | 8 | 9 | @Client.on_message(filters.command(["fwdall"], prefixes=f"{HANDLER}") & filters.me) 10 | async def forward(client: Client, message: Message): 11 | stat = None if len(message.text.split(" ")) < 2 else message.text.split(" ")[1] 12 | if sta is not None: 13 | await message.edit("On it...", parse_mode="html") 14 | try: 15 | target = await client.get_chat(stat) 16 | except: 17 | await message.edit("Unknown target.", parse_mode="html") 18 | target = None 19 | if target is not None: 20 | msgs = [] 21 | async for msg in client.iter_history(message.chat.id, reverse=True): 22 | msgs.append(msg.message_id) 23 | if len(msgs) >= 100: 24 | try: 25 | await client.forward_messages(target.id, message.chat.id, msgs) 26 | except FloodWait as e: 27 | await asyncio.sleep(e.x) 28 | await client.forward_messages(target.id, message.chat.id, msgs) 29 | msgs = [] 30 | if msgs: 31 | try: 32 | await client.forward_messages(target.id, message.chat.id, msgs) 33 | except FloodWait as e: 34 | await asyncio.sleep(e.x) 35 | await client.forward_messages(target.id, message.chat.id, msgs) 36 | await message.edit("Forwarded successfully.", parse_mode="html") 37 | else: 38 | await message.edit("No target passed.", parse_mode="html") 39 | 40 | 41 | modules_help.append( 42 | { 43 | "forwardall": [ 44 | { 45 | "fwdall [target]*": "Foraward all messages to defined target [username/chat_id/chat_link]." 46 | } 47 | ] 48 | } 49 | ) 50 | -------------------------------------------------------------------------------- /annabelle/modules/gban.py: -------------------------------------------------------------------------------- 1 | from config import MY_ID, HANDLER, SUDO_USERS 2 | from pyrogram import filters as vrn 3 | from annabelle.helper_funcs.admin_check import admin_check 4 | from annabelle.helper_funcs.strings import GBAN_TXT 5 | from annabelle import Annabelle 6 | from annabelle.database.gban_db import add_gban, un_gban, check_gban 7 | 8 | import logging 9 | logging = logging.getLogger(__name__) 10 | 11 | @Annabelle.on_message(vrn.command('gban', HANDLER)) 12 | async def gban(Annabelle, message): 13 | if message.from_user.id == MY_ID or message.from_user.id in SUDO_USERS: 14 | if message.reply_to_message: 15 | args = message.text.split(None,1) 16 | if len(args) >= 2: 17 | reason = args[1] 18 | id = message.reply_to_message.from_user.id 19 | member = Annabelle.get_chat_member(message.chat.id, message.reply_to_message.from_user.id) 20 | add_ban(id, reason) 21 | await message.edit(GBAN_TXT.format(message.reply_to_message.from_user.mention, reason)) 22 | else: 23 | reason = "" 24 | else: 25 | await message.edit("You didn't specify whom to gban") 26 | else: 27 | return 28 | 29 | @Annabelle.on_message(vrn.me &vrn.command('ungban', HANDLER) & vrn.group) 30 | async def ungban(Annabelle, message): 31 | if not message.reply_to_message: 32 | message.edit("`reply to message of user who needs to be unbanned!`") 33 | else: 34 | id = message.reply_to_message.from_user.id 35 | x = un_gban(id) 36 | if x is False: 37 | await message.edit("`That user is not globally banned!`") 38 | else: 39 | await message.edit(f"**__{message.reply_to_message.from_user.mention}[{id}]__** has been unbanned") 40 | -------------------------------------------------------------------------------- /annabelle/modules/github.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from annabelle import Annabelle 4 | from config import MY_ID, HANDLER 5 | from pyrogram import filters as vrn 6 | from pyrogram.types.messages_and_media import Message 7 | 8 | 9 | @Annabelle.on_message(filters.command("github", HANDLER)) 10 | async def github(bot:Annabelle, msg:Message) : 11 | if msg.from_user.id == MY_ID : 12 | args = msg.text.split(None, 1) 13 | if len(args) >= 2: 14 | query = args[1] 15 | await msg.edit("`searching github...`") 16 | try : 17 | get_url = f"https://api.github.com/search/users?q={query}" 18 | request1 = requests.get(get_url) 19 | json_data = request1.json() 20 | raw_data = json_data["items"] 21 | data_ = raw_data[0] 22 | url = data_["html_url"] 23 | request2 = requests.get(url) 24 | data = request2.json() 25 | await msg.edit_text(text=f"""

**__Stdout__** 26 | **Query** : `{query}` 27 | 28 | **ID** : `{data["id"]}` 29 | **Url** : ʟɪɴᴋ 30 | **Type** : `{data["type"]}` 31 | **Name** : `{data["name"]}` 32 | **Login** : `{data["login"]}` 33 | **Public Repos** : `{data["public_repos"]}` 34 | **Following** : `{data["following"]}` 35 | **Followers** : `{data["followers"]}` 36 | **Email** : `{data["email"]}` 37 | 38 | **ANABELLE USERBOT** 39 | """) 40 | except : 41 | await msg.edit_text(text=f"**Couldnt find results for** `{query}`") 42 | else: 43 | await message.edit("`Give a username to search`") 44 | 45 | -------------------------------------------------------------------------------- /annabelle/modules/help.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import Message 3 | from config import HANDLER 4 | from annabelle.modules.helpmenu.help_menu import modules_help 5 | 6 | 7 | @Client.on_message(filters.command(["help", "h"], prefixes=f"{HANDLER}") & filters.me) 8 | async def help(client, message: Message): 9 | module_name = " ".join(message.command[1:]) 10 | if module_name == "": 11 | messages = [ 12 | f"""Help for Annabelle Userbot\nFor more help on how to use a command, type {HANDLER}help [module]\n\nAvailable Modules:\n""" 13 | ] 14 | msg_cnt = 0 15 | for mod in modules_help: 16 | help_message = ( 17 | "• " 18 | + list(mod.keys())[0].title() 19 | + ": " 20 | + " ".join( 21 | [ 22 | "" + HANDLER + str(cmd.split()[0]) + "" 23 | for cmd in [ 24 | list(rc.keys())[0] for rc in list(mod.values()).pop(0) 25 | ] 26 | ] 27 | ) 28 | + "\n" 29 | ) 30 | if len(messages[msg_cnt] + help_message) < 2048: 31 | messages[msg_cnt] = messages[msg_cnt] + help_message 32 | else: 33 | msg_cnt += 1 34 | messages.append(help_message) 35 | tc = """\nThe number of modules in the userbot: """ + str( 36 | float(len(modules_help)) 37 | ) 38 | if len(messages[msg_cnt] + tc) < 2048: 39 | messages[msg_cnt] += tc 40 | else: 41 | messages.append(tc) 42 | await message.edit( 43 | messages[0], parse_mode="HTML", disable_web_page_preview=True 44 | ) 45 | messages.pop(0) 46 | for msg in messages: 47 | await message.reply(msg, parse_mode="HTML", disable_web_page_preview=True) 48 | else: 49 | text = f"Help for {module_name}\n\nUsage:\n" 50 | found = False 51 | for mh in modules_help: 52 | if list(mh.keys())[0].lower() == module_name.lower(): 53 | found = True 54 | cmds = list(mh.values()).pop(0) 55 | for u_cmd in cmds: 56 | cmd = list(u_cmd.items())[0] 57 | text += f"""{HANDLER + cmd[0]} - {cmd[1]}\n""" 58 | if found: 59 | await message.edit(text, parse_mode="HTML") 60 | else: 61 | await message.edit(f"Module {module_name} not found!") 62 | 63 | 64 | modules_help.append( 65 | {"help": [{"help [module name]": "To get help. Module name isn't required."}]} 66 | ) 67 | -------------------------------------------------------------------------------- /annabelle/modules/helpers/afk_handler.py: -------------------------------------------------------------------------------- 1 | # functions 2 | 3 | import datetime 4 | from pyrogram import Client, filters 5 | 6 | async def afk_handler(client, message): 7 | try: 8 | global start, end 9 | end = datetime.datetime.now().replace(microsecond=0) 10 | afk_dur = end - start 11 | user_is_bot = message.from_user.is_bot 12 | if user_is_bot is False: 13 | await message.reply_text( 14 | f"I afk {afk_dur}\n" f"Reason: {reason}" 15 | ) 16 | except NameError: 17 | pass 18 | -------------------------------------------------------------------------------- /annabelle/modules/helpers/mirror_func.py: -------------------------------------------------------------------------------- 1 | import os 2 | from PIL import ImageOps, Image 3 | from pyrogram import Client 4 | 5 | async def make(client, message, o): 6 | reply = message.reply_to_message 7 | if reply.photo or reply.sticker: 8 | if reply.photo: 9 | downloads = await client.download_media(reply.photo.file_id) 10 | else: 11 | downloads = await client.download_media(reply.sticker.file_id) 12 | path = f"{downloads}" 13 | img = Image.open(path) 14 | await message.delete() 15 | w, h = img.size 16 | if o in [1, 2]: 17 | if o == 2: 18 | img = ImageOps.mirror(img) 19 | part = img.crop([0, 0, w // 2, h]) 20 | img = ImageOps.mirror(img) 21 | else: 22 | if o == 4: 23 | img = ImageOps.flip(img) 24 | part = img.crop([0, 0, w, h // 2]) 25 | img = ImageOps.flip(img) 26 | img.paste(part, (0, 0)) 27 | img.save(path) 28 | if reply.photo: 29 | return await reply.reply_photo(photo=path) 30 | elif reply.sticker: 31 | return await reply.reply_sticker(sticker=path) 32 | os.remove(path) 33 | 34 | return await message.edit("Need to answer the photo/sticker") 35 | 36 | -------------------------------------------------------------------------------- /annabelle/modules/helpmenu/help_menu.py: -------------------------------------------------------------------------------- 1 | modules_help = [] 2 | requirements_list = [] 3 | -------------------------------------------------------------------------------- /annabelle/modules/inline.py: -------------------------------------------------------------------------------- 1 | from config import MY_ID, HANDLER 2 | from annabelle import Annabelle 3 | from pyrogram import Client 4 | from pyrogram import filters as vrn 5 | from pyrogram.types.messages_and_media import Message 6 | 7 | 8 | @Annabelle.on_message(vrn.command("inline", HANDLER)) 9 | async def inline(bot:Annabelle, msg:Message) : 10 | chat_id = msg.chat.id 11 | peer_id = "Annabellev1_bot" 12 | try : 13 | try : 14 | chat_id = 5292470029 15 | await bot.send_message(chat_id, text="/start") 16 | except : 17 | user_id = 5292470029 18 | await bot.unblock_user(user_id) 19 | await bot.send_message(chat_id=user_id, text="/start") 20 | except : 21 | await bot.resolve_peer(peer_id) 22 | 23 | result = await bot.get_inline_bot_results(bot=peer_id, query="inline") 24 | query_id = result.query_id 25 | result_id = result.results[0].id 26 | await bot.send_inline_bot_result(chat_id, query_id, result_id) 27 | -------------------------------------------------------------------------------- /annabelle/modules/leave.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from annabelle.modules.helpmenu.help_menu import modules_help 4 | from config import HANDLER 5 | 6 | 7 | @Client.on_message( 8 | filters.command(["leave", "lc"], prefixes=f"{HANDLER}") & filters.me 9 | ) 10 | async def leave_chat(client: Client, message): 11 | chat = message.chat.type 12 | chat_id = message.chat.id 13 | if chat in ["group", "supergroup"]: 14 | await message.edit("My Master Doesn't Like This Chat, Leaving Bye...") 15 | await asyncio.sleep(3) 16 | await client.leave_chat(chat_id) 17 | else: 18 | await message.edit("This chat is not in group or supergroup") 19 | 20 | modules_help.append( 21 | {"leave": [{"leave" or "lc": "Leaves chat"}] 22 | ) 23 | 24 | # most of the codes are simple because of time limitation 25 | # there will more features will pushed through some updates 26 | 27 | -------------------------------------------------------------------------------- /annabelle/modules/mirror.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import Message 3 | from config import HANDLER 4 | from annabelle.modules.helpmenu.help_menu import modules_help 5 | from annabelle.modules.helpers.mirror_func import make 6 | 7 | @Client.on_message( 8 | filters.command(["ll", "rr", "dd", "uu"], prefixes=f"{HANDLER}") & filters.me 9 | ) 10 | async def mirror_flip(client: Client, message: Message): 11 | await message.edit("Processing...") 12 | param = {"ll": 1, "rr": 2, "dd": 3, "uu": 4}[message.command[0]] 13 | await make(client, message, param) 14 | 15 | 16 | modules_help.append( 17 | { 18 | "mirror_flip": [ 19 | {"ll [reply on photo or sticker]*": "reflects the left side"}, 20 | {"rr [reply on photo or sticker]*": "reflects the right side"}, 21 | {"uu [reply on photo or sticker]*": "reflects the top"}, 22 | {"dd [reply on photo or sticker]*": "reflects the bottom"}, 23 | ] 24 | } 25 | ) 26 | -------------------------------------------------------------------------------- /annabelle/modules/pin.py: -------------------------------------------------------------------------------- 1 | from config import HANDLER 2 | from annabelle import logger 3 | from annabelle import Annabelle 4 | 5 | from pyrogram import filters 6 | from pyrogram.types import Message 7 | from pyrogram.errors import ChatAdminRequired, RightForbidden, RPCError 8 | 9 | @Annabelle.on_message(filters.command('pin', HANDLER) & filters.group) 10 | async def pin(client: Annabelle, message: Message): 11 | admins = await client.get_chat_member(message.chat.id, message.from_user.id) 12 | if not ((admins.status == "administrator") or (admins.status == "creator")): 13 | await message.reply_text("**Your not allowed to use this.**") 14 | return 15 | if not message.reply_to_message: 16 | await message.reply_text("**Reply to a message to pin.**") 17 | return 18 | try: 19 | message.reply_to_message.pin() 20 | logger.info( 21 | f"I have pinned a message in {message.chat.id}\nMessage link: {message.reply_to_message.link}" 22 | ) 23 | await message.edit("Pinned successfully!") 24 | except ChatAdminRequired: 25 | await message.reply_text("I am not admin here.") 26 | #expect RightForbidden: 27 | #await message.reply_text("I don't have enough rights to pin messages.") 28 | #expect RPCError as e: 29 | #await message.reply_text(f"Some error occurred\n\n*Error:*\n{e}") 30 | 31 | @Annabelle.on_message(filters.command('unpin', HANDLER)) 32 | async def unpin(client: Annabelle, message: Message): 33 | if not ((admins.status == "administrator") or (admins.status == "creator")): 34 | await message.reply_text("**Your not allowed to use this.**") 35 | return 36 | if not message.reply_to_message: 37 | await message.reply_text("**Reply to a message to pin.**") 38 | return 39 | try: 40 | message.reply_to_message.pin() 41 | logger.info( 42 | f"I have unpinned a message in {message.chat.id}\nMessage link: {message.reply_to_message.link}" 43 | ) 44 | await message.edit("Unpinned successfully!") 45 | except ChatAdminRequired: 46 | await message.reply_text("I am not admin here.") 47 | #expect RightForbidden: 48 | #await message.reply_text("I don't have enough rights to unpin messages.") 49 | #expect RPCError as error: 50 | #await message.reply_text(f"Some error occurred\n\n*Error:*\n{error}") 51 | -------------------------------------------------------------------------------- /annabelle/modules/ping.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from time import time 3 | from pyrogram import Client, filters 4 | from pyrogram.types import Message 5 | from config import HANDLER 6 | from annabelle.modules.helpmenu.help_menu import modules_help 7 | 8 | # System Uptime 9 | START_TIME = datetime.utcnow() 10 | TIME_DURATION_UNITS = ( 11 | ("Week", 60 * 60 * 24 * 7), 12 | ("Day", 60 * 60 * 24), 13 | ("Hour", 60 * 60), 14 | ("Min", 60), 15 | ("Sec", 1), 16 | ) 17 | 18 | 19 | async def _human_time_duration(seconds): 20 | if seconds == 0: 21 | return "inf" 22 | parts = [] 23 | for unit, div in TIME_DURATION_UNITS: 24 | amount, seconds = divmod(int(seconds), div) 25 | if amount > 0: 26 | parts.append("{} {}{}".format(amount, unit, "" if amount == 1 else "")) 27 | return ", ".join(parts) 28 | 29 | 30 | @Client.on_message(filters.command(["ping"], prefixes=f"{HNDLR}")) 31 | async def ping(client, m: Message): 32 | start = time() 33 | current_time = datetime.utcnow() 34 | m_reply = await m.reply_text("⚡️") 35 | delta_ping = time() - start 36 | uptime_sec = (current_time - START_TIME).total_seconds() 37 | uptime = await _human_time_duration(int(uptime_sec)) 38 | await m_reply.edit( 39 | f"🤴I'm Online\n📟`{delta_ping * 1000:.3f} ms` \n⏱️Uptime - `{uptime}`" 40 | ) 41 | 42 | 43 | modules_help.append({"ping": [{"ping": "To find out the ping"}]}) 44 | -------------------------------------------------------------------------------- /annabelle/modules/pmpermit.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from asyncio import sleep 3 | from pyrogram import filters 4 | from config import SUDO_USERS, HANDLER 5 | from pmpermit_db import check_permit, add_permit, del_permit 6 | from annabelle import Annabelle 7 | PM_PERMIT = False 8 | 9 | @Annabelle.on_message(filters.command('a', HANDLER) & filters.me) 10 | async def addpm(Annabelle, message): 11 | if message.reply_to_message: 12 | id = message.reply_to_message.from_user.id 13 | x = add_permit(id) 14 | if x is False: 15 | await message.edit("`That user is already permitted`") 16 | asyncio.sleep(3) 17 | await message.delete() 18 | else: 19 | await message.edit("`That user can send pm messages`") 20 | else: 21 | await message.edit("`Reply to that user's message`") 22 | 23 | @Annabelle.on_message(filters.command('una', HANDLER) & filters.me) 24 | async def delpm(Annabelle, message): 25 | if messege.reply_to_message: 26 | id = message.reply_to_message.from_user.id 27 | x = del_permit(id) 28 | if x is False: 29 | await message.edit("`That user was not even approved`") 30 | else: 31 | await message.edit("`That user is unapproved to pm you`") 32 | else: 33 | await message.edit("`Reply to that user's message`") 34 | 35 | @Annabelle.on_message(filters.command('pmpermit', HANDLER) & filters.me) 36 | async def togglepm(Annabelle, message, PM_PERMIT): 37 | args = message.text.split(None, 1) 38 | if len(args) >= 2: 39 | toggle = args[1] 40 | if toggle.lower() in ['on', 'yes', 'true']: 41 | PM_PERMIT = True 42 | await message.edit("`PM guard turned on`") 43 | elif toggle.lower() in ['no', 'off', 'false']: 44 | PM_PERMIT = True 45 | await message.edit("`PM guard turned off`") 46 | else: 47 | await message.edit("`What are you saying?`") 48 | else: 49 | await message.edit("`Command incomplete`") 50 | 51 | @Annabelle.on_message(filters.private & filters.incoming) 52 | async def testpm(Annabelle, message, PM_PERMIT): 53 | while PM_PERMIT is True: 54 | id = message.from_user.id 55 | x = check_permit(id) 56 | if x is not True: 57 | await message.delete() 58 | await Annabelle.send_message(message.chat.id, PM_TEXT) 59 | else: 60 | continue 61 | -------------------------------------------------------------------------------- /annabelle/modules/purge.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from config import HANDLER 4 | from annabelle.modules.helpmenu.help_menu import modules_help 5 | 6 | from pyrogram.types import Message 7 | from pyrogram import Client, filters 8 | 9 | @Client.on_message(filters.command("del", HANDLER) & filters.me) 10 | async def del_msg(client: Client, message: Message): 11 | if not message.reply_to_message: 12 | await message.reply_text("Reply to message to delete") 13 | return 14 | message_id = message.reply_to_message.message_id 15 | await message.delete() 16 | await client.delete_messages( 17 | chat_id=message.chat.id, 18 | message_ids=message_id, 19 | ) 20 | k = await message.reply("I've deleted the message for you") 21 | await asyncio.sleep(3) 22 | await k.delete() 23 | 24 | @Client.on_message(filters.command("purge", HANDLER) & filters.me) 25 | async def purge(client: Client, message: Message): 26 | messages_to_purge = [] 27 | if not message.reply_to_message: 28 | await message.reply_text("Reply to message to purge") 29 | return 30 | async for msg in client.iter_history( 31 | chat_id=message.chat.id, 32 | offset_id=message.reply_to_message.message_id, 33 | reverse=True, 34 | ): 35 | messages_to_purge.append(msg.message_id) 36 | for msgs in [ 37 | messages_to_purge[i : i + 1000] for i in range(0, len(messages_to_purge), 1000) 38 | ]: 39 | await client.delete_messages(message.chat.id, msgs) 40 | await asyncio.sleep(1) 41 | await message.reply("Purge completed") 42 | await asyncio.sleep(2) 43 | await message.delete() 44 | 45 | 46 | modules_help.append( 47 | { 48 | "purge": [ 49 | { 50 | "purge [reply]*": "Reply to a message after which you want to delete messages" 51 | }, 52 | {"del [reply]*": "Reply to the message you want to delete"}, 53 | ] 54 | } 55 | ) 56 | -------------------------------------------------------------------------------- /annabelle/modules/qoutly.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os 3 | from io import BytesIO 4 | import requests 5 | from pyrogram import Client, errors, filters, types 6 | from config import HANDLER 7 | from annabelle.modules.helpmenu.help_menu import modules_help 8 | 9 | 10 | @Client.on_message(filters.command(["q", "quote"], prefixes=f"{HANDLER}") & filters.me) 11 | async def quote_cmd(client: Client, message: types.Message): 12 | if not message.reply_to_message: 13 | return await message.edit("Specify message(s) for quote") 14 | 15 | if len(message.command) > 1 and message.command[1].isdigit(): 16 | count = int(message.command[1]) 17 | if count < 1: 18 | count = 1 19 | elif count > 15: 20 | count = 15 21 | else: 22 | count = 1 23 | 24 | is_png = "!png" in message.command or "!file" in message.command 25 | send_for_me = "!me" in message.command or "!ls" in message.command 26 | no_reply = "!noreply" in message.command or "!nr" in message.command 27 | 28 | messages = list( 29 | filter( 30 | lambda x: x.message_id < message.message_id, 31 | await client.get_messages( 32 | message.chat.id, 33 | range( 34 | message.reply_to_message.message_id, 35 | message.reply_to_message.message_id + count, 36 | ), 37 | ), 38 | ) 39 | ) 40 | 41 | if no_reply: 42 | messages[0].reply_to_message = None 43 | 44 | if send_for_me: 45 | await message.delete() 46 | message = await client.send_message("me", "Generating...") 47 | else: 48 | await message.edit("Generating...") 49 | 50 | url = "https://quotes.fl1yd.su/generate" 51 | params = { 52 | "messages": [ 53 | await render_message(client, msg) for msg in messages if not msg.empty 54 | ], 55 | "quote_color": "#162330", 56 | "text_color": "#fff", 57 | } 58 | 59 | response = requests.post(url, json=params) 60 | if not response.ok: 61 | return await message.edit( 62 | f"Quotes API error!\n" f"{response.text}" 63 | ) 64 | 65 | file_io = BytesIO(response.content) 66 | file_io.name = "sticker.png" if is_png else "sticker.webp" 67 | await message.edit("Sending...") 68 | 69 | try: 70 | func = client.send_document if is_png else client.send_sticker 71 | chat_id = "me" if send_for_me else message.chat.id 72 | await func(chat_id, file_io) 73 | except errors.RPCError as e: # no rights to send stickers, etc 74 | await message.edit(f"Telegram API error!\n" f"{e}") 75 | else: 76 | await message.delete() 77 | 78 | 79 | @Client.on_message( 80 | filters.command(["fq", "fakequote"], prefixes=f"{HANDLER}") & filters.me 81 | ) 82 | async def fake_quote_cmd(client: Client, message: types.Message): 83 | if not message.reply_to_message: 84 | return await message.edit("Specify message for fake quote") 85 | 86 | is_png = "!png" in message.command or "!file" in message.command 87 | send_for_me = "!me" in message.command or "!ls" in message.command 88 | no_reply = "!noreply" in message.command or "!nr" in message.command 89 | 90 | fake_quote_text = " ".join( 91 | [ 92 | arg 93 | for arg in message.command[1:] 94 | if arg not in ["!png", "!file", "!me", "!ls", "!noreply", "!nr"] 95 | ] # remove some special arg words 96 | ) 97 | 98 | if not fake_quote_text: 99 | return await message.edit("Fake quote text is empty") 100 | 101 | q_message = await client.get_messages( 102 | message.chat.id, message.reply_to_message.message_id 103 | ) 104 | q_message.text = fake_quote_text 105 | q_message.entities = None 106 | if no_reply: 107 | q_message.reply_to_message = None 108 | 109 | if send_for_me: 110 | await message.delete() 111 | message = await client.send_message("me", "Generating...") 112 | else: 113 | await message.edit("Generating...") 114 | 115 | url = "https://quotes.fl1yd.su/generate" 116 | params = { 117 | "messages": [await render_message(client, q_message)], 118 | "quote_color": "#162330", 119 | "text_color": "#fff", 120 | } 121 | 122 | response = requests.post(url, json=params) 123 | if not response.ok: 124 | return await message.edit( 125 | f"Quotes API error!\n" f"{response.text}" 126 | ) 127 | 128 | file_io = BytesIO(response.content) 129 | file_io.name = "sticker.png" if is_png else "sticker.webp" 130 | await message.edit("Sending...") 131 | 132 | try: 133 | func = client.send_document if is_png else client.send_sticker 134 | chat_id = "me" if send_for_me else message.chat.id 135 | await func(chat_id, file_io) 136 | except errors.RPCError as e: # no rights to send stickers, etc 137 | await message.edit(f"Telegram API error!\n" f"{e}") 138 | else: 139 | await message.delete() 140 | 141 | 142 | files_cache = {} 143 | 144 | 145 | async def render_message(app: Client, message: types.Message) -> dict: 146 | async def get_file(file_id) -> str: 147 | if file_id in files_cache: 148 | return files_cache[file_id] 149 | 150 | file_name = await app.download_media(file_id) 151 | with open(file_name, "rb") as f: 152 | content = f.read() 153 | os.remove(file_name) 154 | data = base64.b64encode(content).decode() 155 | files_cache[file_id] = data 156 | return data 157 | 158 | # text 159 | if message.photo: 160 | text = message.caption if message.caption else "" 161 | elif message.poll: 162 | text = get_poll_text(message.poll) 163 | elif message.sticker: 164 | text = "" 165 | else: 166 | text = get_reply_text(message) 167 | 168 | # media 169 | if message.photo: 170 | media = await get_file(message.photo.file_id) 171 | elif message.sticker: 172 | media = await get_file(message.sticker.file_id) 173 | else: 174 | media = "" 175 | 176 | # entities 177 | entities = [] 178 | if message.entities: 179 | for entity in message.entities: 180 | entities.append( 181 | { 182 | "offset": entity.offset, 183 | "length": entity.length, 184 | "type": entity.type, 185 | } 186 | ) 187 | 188 | def move_forwards(msg: types.Message): 189 | if msg.forward_from: 190 | msg.from_user = msg.forward_from 191 | elif msg.forward_sender_name: 192 | msg.from_user.id = 0 193 | msg.from_user.first_name = msg.forward_sender_name 194 | msg.from_user.last_name = "" 195 | elif msg.forward_from_chat: 196 | msg.sender_chat = msg.forward_from_chat 197 | 198 | move_forwards(message) 199 | 200 | # author 201 | author = {} 202 | if message.from_user: 203 | author["id"] = message.from_user.id 204 | author["name"] = get_full_name(message.from_user) 205 | if message.chat.type != "supergroup" or message.from_user.id == 0: 206 | author["rank"] = "" 207 | else: 208 | try: 209 | member = await message.chat.get_member(message.from_user.id) 210 | except errors.UserNotParticipant: 211 | author["rank"] = "" 212 | else: 213 | author["rank"] = getattr(member, "title", "") or ( 214 | "owner" 215 | if member.status == "creator" 216 | else "admin" 217 | if member.status == "administrator" 218 | else "" 219 | ) 220 | 221 | if message.from_user.id == 0 or not message.from_user.photo: 222 | author["avatar"] = "" 223 | else: 224 | author["avatar"] = await get_file(message.from_user.photo.big_file_id) 225 | else: 226 | author["id"] = message.sender_chat.id 227 | author["name"] = message.sender_chat.title 228 | author["rank"] = "channel" if message.sender_chat.type == "channel" else "" 229 | 230 | if message.sender_chat.photo: 231 | author["avatar"] = await get_file(message.sender_chat.photo.big_file_id) 232 | else: 233 | author["avatar"] = "" 234 | author["via_bot"] = message.via_bot.username if message.via_bot else "" 235 | 236 | # reply 237 | reply = {} 238 | reply_msg = message.reply_to_message 239 | if reply_msg and not reply_msg.empty: 240 | move_forwards(reply_msg) 241 | 242 | if reply_msg.from_user: 243 | reply["id"] = reply_msg.from_user.id 244 | reply["name"] = get_full_name(reply_msg.from_user) 245 | else: 246 | reply["id"] = reply_msg.sender_chat.id 247 | reply["name"] = reply_msg.sender_chat.title 248 | 249 | reply["text"] = get_reply_text(reply_msg) 250 | 251 | return { 252 | "text": text, 253 | "media": media, 254 | "entities": entities, 255 | "author": author, 256 | "reply": reply, 257 | } 258 | 259 | 260 | def get_audio_text(audio: types.Audio) -> str: 261 | if audio.title and audio.performer: 262 | return f" ({audio.title} — {audio.performer})" 263 | elif audio.title: 264 | return f" ({audio.title})" 265 | elif audio.performer: 266 | return f" ({audio.performer})" 267 | else: 268 | return "" 269 | 270 | 271 | def get_reply_text(reply: types.Message) -> str: 272 | return ( 273 | "📷 Photo" + ("\n" + reply.caption if reply.caption else "") 274 | if reply.photo 275 | else get_reply_poll_text(reply.poll) 276 | if reply.poll 277 | else "📍 Location" 278 | if reply.location or reply.venue 279 | else "👤 Contact" 280 | if reply.contact 281 | else "🖼 GIF" 282 | if reply.animation 283 | else "🎧 Music" + get_audio_text(reply.audio) 284 | if reply.audio 285 | else "📹 Video" 286 | if reply.video 287 | else "📹 Videomessage" 288 | if reply.video_note 289 | else "🎵 Voice" 290 | if reply.voice 291 | else (reply.sticker.emoji + " " if reply.sticker.emoji else "") + "Sticker" 292 | if reply.sticker 293 | else "💾 File " + reply.document.file_name 294 | if reply.document 295 | else "🎮 Game" 296 | if reply.game 297 | else "🎮 set new record" 298 | if reply.game_high_score 299 | else f"{reply.dice.emoji} - {reply.dice.value}" 300 | if reply.dice 301 | else ( 302 | "👤 joined the group" 303 | if reply.new_chat_members[0].id == reply.from_user.id 304 | else "👤 invited %s to the group" 305 | % (get_full_name(reply.new_chat_members[0])) 306 | ) 307 | if reply.new_chat_members 308 | else ( 309 | "👤 left the group" 310 | if reply.left_chat_member.id == reply.from_user.id 311 | else "👤 removed %s" % (get_full_name(reply.left_chat_member)) 312 | ) 313 | if reply.left_chat_member 314 | else f"✏ changed group name to {reply.new_chat_title}" 315 | if reply.new_chat_title 316 | else "🖼 changed group photo" 317 | if reply.new_chat_photo 318 | else "🖼 removed group photo" 319 | if reply.delete_chat_photo 320 | else "📍 pinned message" 321 | if reply.pinned_message 322 | else "🎤 started a new video chat" 323 | if reply.voice_chat_started 324 | else "🎤 ended the video chat" 325 | if reply.voice_chat_ended 326 | else "🎤 invited participants to the video chat" 327 | if reply.voice_chat_members_invited 328 | else "👥 created the group" 329 | if reply.group_chat_created or reply.supergroup_chat_created 330 | else "👥 created the channel" 331 | if reply.channel_chat_created 332 | else reply.text or "unsupported message" 333 | ) 334 | 335 | 336 | def get_poll_text(poll: types.Poll) -> str: 337 | text = get_reply_poll_text(poll) + "\n" 338 | 339 | text += poll.question + "\n" 340 | for option in poll.options: 341 | text += f"- {option.text}" 342 | if option.voter_count > 0: 343 | text += f" ({option.voter_count} voted)" 344 | text += "\n" 345 | 346 | text += f"Total: {poll.total_voter_count} voted" 347 | 348 | return text 349 | 350 | 351 | def get_reply_poll_text(poll: types.Poll) -> str: 352 | if poll.is_anonymous: 353 | text = "📊 Anonymous poll" if poll.type == "regular" else "📊 Anonymous quiz" 354 | else: 355 | text = "📊 Poll" if poll.type == "regular" else "📊 Quiz" 356 | if poll.is_closed: 357 | text += " (closed)" 358 | 359 | return text 360 | 361 | 362 | def get_full_name(user: types.User) -> str: 363 | name = user.first_name 364 | if user.last_name: 365 | name += " " + user.last_name 366 | return name 367 | 368 | 369 | modules_help.append( 370 | { 371 | "squotes": [ 372 | { 373 | "q [reply]* [count] [args]": "Generate a quote\nAvailable args: !png — send a quote as png; !me — send a quote to saved messages; !noreply - make a quote without reply message" 374 | }, 375 | {"fq [reply]* [args] [text]": "Generate a fake quote"}, 376 | ] 377 | } 378 | ) 379 | -------------------------------------------------------------------------------- /annabelle/modules/screenshot.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.raw import functions 4 | from pyrogram.types import Message 5 | from config import HANDLER 6 | from annabelle.modules.helpmenu.help_menu import modules_help 7 | 8 | @Client.on_message( 9 | filters.command(["scr", "screenshot"], prefixes=f"{HANDLER}") & filters.me 10 | ) 11 | async def scrshot(client: Client, message: Message): 12 | quantity = int(message.command[1]) 13 | chat = message.chat.id 14 | await message.delete() 15 | for _ in range(quantity): 16 | await asyncio.sleep(2) 17 | await client.send( 18 | functions.messages.SendScreenshotNotification( 19 | peer = await client.resolve_peer(chat), 20 | reply_to_msg_id = 0, 21 | random_id = rnd_id(), 22 | ) 23 | ) 24 | 25 | 26 | modules_help.append( 27 | { 28 | "screenshot": [ 29 | { 30 | "scr [amount of screenshots]": "Take a screenshot\nThis only works in private messages!" 31 | } 32 | ] 33 | } 34 | ) 35 | -------------------------------------------------------------------------------- /annabelle/modules/sendmod.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | from pyrogram import Client, filters 4 | from pyrogram.types import Message 5 | from config import HANDLER 6 | from annabelle.modules.helpmenu.help_menu import modules_help 7 | 8 | 9 | @Client.on_message(filters.command(["sendmod", "sm"], prefixes=f"{HANDLER}") & filters.me) 10 | async def sendmod(client: Client, message: Message): 11 | module_name = message.command[1] 12 | try: 13 | await message.edit("Dispatch...") 14 | text = f"Help for {module_name}\n\nUsage:\n" 15 | found = False 16 | for mh in modules_help: 17 | if list(mh.keys())[0].lower() == module_name.lower(): 18 | found = True 19 | cmds = list(mh.values()).pop(0) 20 | for u_cmd in cmds: 21 | cmd = list(u_cmd.items())[0] 22 | text += f"""{HNDLR + cmd[0]} - {cmd[1]}\n""" 23 | if not found: 24 | text = "Module {module_name} not found!" 25 | 26 | if os.path.isfile(f"Mister_Dark_Prince/{module_name.lower()}.py"): 27 | await client.send_document( 28 | message.chat.id, 29 | f"Mister_Dark_Prince/{module_name.lower()}.py", 30 | caption=text, 31 | ) 32 | elif os.path.isfile( 33 | f"Mister_Dark_Prince/custom_modules/{module_name.lower()}.py" 34 | ): 35 | await client.send_document( 36 | message.chat.id, 37 | f"Mister_Dark_Prince/custom_modules/{module_name.lower()}.py", 38 | caption=text, 39 | ) 40 | await message.delete() 41 | except: 42 | await message.edit("Invalid module name!") 43 | await asyncio.sleep(5) 44 | await message.delete() 45 | 46 | 47 | modules_help.append( 48 | { 49 | "sendmod": [ 50 | {"sendmod [module name]*": "Send one of the modules to the interlocutor"} 51 | ] 52 | } 53 | ) 54 | -------------------------------------------------------------------------------- /annabelle/modules/set.py: -------------------------------------------------------------------------------- 1 | from annabelle import Annabelle 2 | from pyrogram import filters as vrn 3 | 4 | @Annabelle.on_message(vrn.command('setemoji', HANDLER)) 5 | async def setemoji(Annabelle, message): 6 | if message.from_user.id == MY_ID: 7 | args = message.text.split(None, 1) 8 | if len(args) >= 2: 9 | ALIVE_EMOJI = args[1] 10 | await message.edit(f"`ALIVE_EMOJI has been set to {ALIVE_EMOJI}") 11 | 12 | else: 13 | await message.edit("`At least mention what to reply with!`") 14 | 15 | @Annabelle.on_message(vrn.command('alivepic', HANDLER)) 16 | async def setpic(Annabelle, message): 17 | if message.from_user.id == MY_ID: 18 | args = message.text.split(None, 1) 19 | if len(args) >= 2: 20 | x = args[1] 21 | if x.endswith["jpg", "jpeg", "png"]: 22 | ALIVE_IMG = x 23 | await message.edit(f"ALIVE_IMG has been set to {ALIVE_IMG}") 24 | else: 25 | await message.edit("`Available types are jpg, jpeg, png.`") 26 | else: 27 | await message.edit("`Set to what?`") 28 | -------------------------------------------------------------------------------- /annabelle/modules/spam.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.types import Message 4 | from config import HANDLER 5 | from annabelle.modules.helpmenu.help_menu import modules_help 6 | 7 | 8 | @Client.on_message(filters.command("spamstats", prefixes=f"{HANDLER}") & filters.me) 9 | async def statspam(client: Client, message: Message): 10 | quantity = message.command[1] 11 | spam_text = " ".join(message.command[2:]) 12 | quantity = int(quantity) 13 | await message.delete() 14 | for _ in range(quantity): 15 | msg = await client.send_message(message.chat.id, spam_text) 16 | await asyncio.sleep(0.1) 17 | await msg.delete() 18 | await asyncio.sleep(0.1) 19 | 20 | 21 | @Client.on_message(filters.command("spam", prefixes=f"{HANDLER}") & filters.me) 22 | async def spam(client: Client, message: Message): 23 | quantity = message.command[1] 24 | spam_text = " ".join(message.command[2:]) 25 | quantity = int(quantity) 26 | await message.delete() 27 | 28 | if message.reply_to_message: 29 | reply_to_id = message.reply_to_message.message_id 30 | for _ in range(quantity): 31 | await client.send_message( 32 | message.chat.id, spam_text, reply_to_message_id=reply_to_id 33 | ) 34 | await asyncio.sleep(0.15) 35 | return 36 | 37 | for _ in range(quantity): 38 | await client.send_message(message.chat.id, spam_text) 39 | await asyncio.sleep(0.15) 40 | 41 | 42 | @Client.on_message(filters.command("fastspam", prefixes=f"{HANDLER}") & filters.me) 43 | async def fastspam(client: Client, message: Message): 44 | quantity = message.command[1] 45 | spam_text = " ".join(message.command[2:]) 46 | quantity = int(quantity) 47 | await message.delete() 48 | 49 | if message.reply_to_message: 50 | reply_to_id = message.reply_to_message.message_id 51 | for _ in range(quantity): 52 | await client.send_message( 53 | message.chat.id, spam_text, reply_to_message_id=reply_to_id 54 | ) 55 | await asyncio.sleep(0.02) 56 | return 57 | 58 | for _ in range(quantity): 59 | await client.send_message(message.chat.id, spam_text) 60 | await asyncio.sleep(0.02) 61 | 62 | 63 | @Client.on_message(filters.command("slowspam", prefixes=f"{HANDLER}") & filters.me) 64 | async def slowspam(client: Client, message: Message): 65 | quantity = message.command[1] 66 | spam_text = " ".join(message.command[2:]) 67 | quantity = int(quantity) 68 | await message.delete() 69 | 70 | if message.reply_to_message: 71 | reply_to_id = message.reply_to_message.message_id 72 | for _ in range(quantity): 73 | await client.send_message( 74 | message.chat.id, spam_text, reply_to_message_id=reply_to_id 75 | ) 76 | await asyncio.sleep(0.9) 77 | return 78 | 79 | for _ in range(quantity): 80 | await client.send_message(message.chat.id, spam_text) 81 | await asyncio.sleep(0.9) 82 | 83 | 84 | modules_help.append( 85 | { 86 | "spam": [ 87 | {"spam [amount of spam]* [spam text]*": "Start spam"}, 88 | {"statspam [amount of spam]* [spam text]*": "Send and delete"}, 89 | {"fastspam [amount of spam]* [spam text]*": "Start fast spam"}, 90 | {"slowspam [amount of spam]* [spam text]*": "Start slow spam"}, 91 | ] 92 | } 93 | ) 94 | -------------------------------------------------------------------------------- /annabelle/modules/tagall.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.types import Message 4 | from config import HANDLER 5 | from annabelle.modules.helpmenu.help_menu import modules_help 6 | 7 | @Client.on_message(filters.command("tagall", prefixes=f"{HANDLER}") & filters.me) 8 | async def tagall(client: Client, message: Message): 9 | await message.delete() 10 | chat_id = message.chat.id 11 | string = "" 12 | limit = 1 13 | icm = client.iter_chat_members(chat_id) 14 | async for member in icm: 15 | tag = member.user.username 16 | if limit <= 10: 17 | string += f"@{tag}\n" if tag != None else f"{member.user.mention}\n" 18 | limit += 1 19 | else: 20 | await client.send_message(chat_id, text=string) 21 | limit = 1 22 | string = "" 23 | await asyncio.sleep(2) 24 | 25 | 26 | modules_help.append({"tagall": [{"tagall": "Tag all members"}]}) 27 | -------------------------------------------------------------------------------- /annabelle/modules/thumbnail.py: -------------------------------------------------------------------------------- 1 | import ytthumb 2 | from pyrogram import Client, filters as vrn 3 | 4 | @Client.on_message(vrn.command('thumb', prefixes=f"{HANDLER}) & filter.me) 5 | async def thumb(Client, message): 6 | try: 7 | args = message.text.split(None, 1) 8 | d=await message.reply("```Processing...```") 9 | link=args[1] 10 | thumb=ytthumb.thumbnail(video=link, 11 | quality="maxres") 12 | await message.reply_photo(photo=thumb) 13 | await d.delete() 14 | except: 15 | await message.reply("No results found!\nTry to check your link..") 16 | await d.delete() 17 | -------------------------------------------------------------------------------- /annabelle/modules/typewritter.py: -------------------------------------------------------------------------------- 1 | # don't type large text.. Your account will be banned ❗️ 2 | 3 | import asyncio 4 | import time 5 | from pyrogram import Client, filters 6 | from pyrogram.errors import FloodWait 7 | from pyrogram.types import Message 8 | from config import HANDLER 9 | from annabelle.modules.helpmenu.help_menu import modules_help 10 | 11 | @Client.on_message(filters.command("type", prefixes=f"{HANDLER}") & filters.me) 12 | async def type(client: Client, message: Message): 13 | orig_text = " ".join(message.command[1:]) 14 | text = orig_text 15 | tbp = "" 16 | typing_symbol = "⌨️" 17 | 18 | while tbp != text: 19 | try: 20 | await message.edit(tbp + typing_symbol) 21 | await asyncio.sleep(0.1) 22 | 23 | tbp += text[0] 24 | text = text[1:] 25 | 26 | await message.edit(tbp) 27 | await asyncio.sleep(0.1) 28 | 29 | except FloodWait as e: 30 | time.sleep(e.x) 31 | 32 | 33 | modules_help.append( 34 | { 35 | "type": [ 36 | { 37 | "type [text]*": "Typing emulation\nDon't use for a lot of characters. Your account may be banned!" 38 | } 39 | ] 40 | } 41 | ) 42 | -------------------------------------------------------------------------------- /annabelle/modules/wiki.py: -------------------------------------------------------------------------------- 1 | import wikipedia 2 | from pyrogram import Client, filters 3 | from pyrogram.types import Message 4 | from config import HANDLER 5 | from annabelle.modules.helpmenu.help_menu import modules_help 6 | 7 | @Client.on_message(filters.command("wiki", prefixes=f"{HANDLER}") & filters.me) 8 | async def wiki(client: Client, message: Message): 9 | lang = message.command[1] 10 | user_request = " ".join(message.command[2:]) 11 | if user_request == "": 12 | wikipedia.set_lang("en") 13 | user_request = " ".join(message.command[1:]) 14 | try: 15 | if lang == "ml": 16 | wikipedia.set_lang("ml") 17 | 18 | result = wikipedia.summary(user_request) 19 | await message.edit( 20 | f"""Request: 21 | {user_request} 22 | Result: 23 | {result}""" 24 | ) 25 | 26 | except Exception as exc: 27 | await message.edit( 28 | f"""Request: 29 | {user_request} 30 | Result: 31 | {exc}""" 32 | ) 33 | 34 | 35 | modules_help.append( 36 | {"wikipedia": [{"wiki [lang] [request]*": "Search in Russian Wikipedia"}]} 37 | ) 38 | 39 | requirements_list.append("wikipedia") 40 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Annabelle UserBot", 3 | "description": "A powerful userbot fully running in pyrogram .", 4 | "keywords": [ 5 | "Telegram", 6 | "Userbot", 7 | "Heroku", 8 | "PyrogramUserBot" 9 | ], 10 | "repository": "https://github.com/AnnabelleTG/Annabelle", 11 | "website": "https://t.me/AnnabelleUB", 12 | "success_url": "https://github.com/AnnabelleTG/Annabelle", 13 | "env": { 14 | "API_ID": { 15 | "description": "API_ID from website or bot", 16 | "required": "True" 17 | }, 18 | "API_HASH": { 19 | "description": "You can get this from @s4h_api_idbot", 20 | "required": "True" 21 | }, 22 | "BOT_TOKEN": { 23 | "description": "Give a Bot token. Get it from @botfather", 24 | "required": "True" 25 | }, 26 | "SESSION_STRING": { 27 | "description": "Your telegram session must be pyrogram session use @Pyrogram_String_Bot", 28 | "required": "True" 29 | }, 30 | "DATABASE_NAME": { 31 | "description": "Your mongodb database name (use any name)", 32 | "required": "True" 33 | }, 34 | "DATABASE_URL": { 35 | "description": "Mongodb database url", 36 | "required": "True" 37 | }, 38 | "HANDLER": { 39 | "description": "You can set your prefix example : .,?+", 40 | "required": "True" 41 | }, 42 | "SUDO_USERS": { 43 | "description": "ID of users who can use your bot's certain other than you", 44 | "required": "False" 45 | }, 46 | "MY_ID": { 47 | "description": "Your telegram id", 48 | "required": "True" 49 | } 50 | }, 51 | "stack": "heroku-20", 52 | "formation": { 53 | "worker": { 54 | "quantity": 1, 55 | "size": "free" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | from config import API_ID, API_HASH, BOT_TOKEN 3 | 4 | mainbot = Client( 5 | api_id = API_ID, 6 | api_hash = API_HASH, 7 | bot_token = BOT_TOKEN, 8 | session_name = "Annabelle-userbot") 9 | 10 | 11 | print("Mainbot has started!") 12 | mainbot.run() 13 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os import environ 3 | 4 | # vars that need to run the bot 5 | API_ID = int(environ['API_ID']) 6 | API_HASH = environ['API_HASH'] 7 | SESSION_STRING = environ['SESSION_STRING'] 8 | BOT_TOKEN = environ['BOT_TOKEN'] 9 | HANDLER = environ.get(('HANDLER')) 10 | MY_ID = int(environ.get('MY_ID')) 11 | SUDO_USERS = environ.get('SUDO_USERS', MY_ID).split() 12 | DATABASE_NAME = str(environ.get('DATABASE_NAME')) 13 | DATABASE_URL = environ.get('DATABASE_URL') 14 | CHANNEL_ID = environ.get('CHANNEL_ID') 15 | CMD_HELP = {} 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | shop: 4 | build: . 5 | environment: 6 | API_ID: $API_ID 7 | API_HASH: $API_HASH 8 | BOT_TOKEN: $BOT_TOKEN 9 | DATABASE_URL: $DATABASE_URL 10 | HANDLER: $HANDLER 11 | DATABASE_NAME: $DATABASE_NAME 12 | SESSION_STRING: $SESSION_STRING 13 | MY_ID: $MY_ID 14 | SUDO_USERS: $SUDO_USERS 15 | -------------------------------------------------------------------------------- /mainbot/start.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters as vrn 2 | from bot import mainbot 3 | from config import HANDLER, MY_ID 4 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 5 | 6 | import logging 7 | 8 | @mainbot.on_message(vrn.command('start', HANDLER) & vrn.private) 9 | async def start(mainbot, message): 10 | await message.reply_photo( 11 | photo = {}, 12 | caption = f"Hola {message.from_user}, I am the horrifying Annabelle userbot made for [this person](t.me/user?id={MY_ID}). The messages you send here will be forwarded to my master", 13 | reply_markup = InlineKeyboardMarkup([ 14 | [InlineKeyboardMarkup("Deploy your own bot", url="https://github.com/AnnabelleTG/Annabelle")], 15 | [InlineKeyboardButton("Support Channel", url="t.me/annabelleUB"), InlineKeyboardButton("Group", url="https://t.me/AnnaBelleSupportChat")] 16 | ]) 17 | ) 18 | 19 | @mainbot.on_message(vrn.incoming & vrn.private) 20 | async def frwd(mainbot, message): 21 | try: 22 | USER_ID = message.from_user.mention 23 | await mainbot.forward_message(message.from_user.id, MY_ID) 24 | except: 25 | mainbot.send_message(MY_ID, f"{USER_ID} is spamming me! I am not able to forward his messages") 26 | 27 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp 2 | APScheduler==3.7.0 3 | cowpy 4 | dnspython 5 | git-python 6 | pillow 7 | pip-chill 8 | psutil 9 | ptable 10 | pymongo 11 | git+https://github.com/subinps/pyrogram.git@session 12 | python-dotenv 13 | python-git 14 | requests-async 15 | speedtest-cli==2.1.3 16 | tgcrypto 17 | yourls 18 | humanize 19 | thisapidoesnotexist 20 | aiofiles 21 | svglib 22 | reportlab 23 | spotipy 24 | ftpretty 25 | youtube_dl 26 | qrcode[pil] 27 | opencv-python 28 | humanize 29 | pytz 30 | wikipedia 31 | wget 32 | requests 33 | asyncio 34 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.9.6 2 | -------------------------------------------------------------------------------- /start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cyan="\033[1;36m" 4 | reset="\033[0m" 5 | white="\033[1;97m" 6 | red="\033[1;91m" 7 | 8 | echo -e "${white}[ ${red}* ${white}] ${cyan} Installing required packages !!${reset}\n" 9 | 10 | packages=(git python) 11 | 12 | for pkg in "${packages[@]}" ; do 13 | if ! hash ${pkg} > /dev/null 2>&1 ; then 14 | echo -e "\n${white}[ ${red}* ${white}] ${cyan} Installing ${pkg} ${reset}\n" 15 | apt install "${pkg}" -y || sudo apt install "${pkg}" -y 16 | fi 17 | 18 | done 19 | 20 | if [ ! -d "./annabelle" ] ; then 21 | 22 | echo -e "\n${white}[ ${red}* ${white}] ${cyan} Cloning into Annabelle ${reset}\n" 23 | git clone https://github.com/AnnabelleTG/Annabelle 24 | 25 | echo -e "${white}[ ${red}* ${white}] ${cyan} Instaling pip modules !${reset}\n" 26 | pip install -r ./Annabelle/requirements.txt 27 | 28 | echo "Starting Annabelle!" 29 | python3 ./Annabelle/bot.py & 30 | python3 ./Annabelle/annabelle.py 31 | --------------------------------------------------------------------------------