diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index f7106d7575eb03d6a88fa319869c1e172e4bacc5..1a553d88e7e4f94cc31c7fd4decafa5e195b37ea 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -15,7 +15,7 @@ jobs: - name: Run pre-commit autoupdate run: pre-commit autoupdate - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.GITHUB_TOKEN }} branch: update/pre-commit-autoupdate diff --git a/.gitignore b/.gitignore index a49dcacd3e71723a64b208e6a9c6fcde6ad4eb75..0e30981e3e7aaec1da1512d6c013577ea65c4826 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,17 @@ *.session *.session-journal -Powers/config.py -Powers/vars.py .vscode/ postgres-data/ *.env !sample.env logs/ Powers/local_vars.py -Powers/vars.py .idea/ +scrapped/ # Byte-compiled / optimized / DLL files __pycache__/ +Youtube/ *.py[cod] *$py.class diff --git a/Powers/__init__.py b/Powers/__init__.py index 04196bf288a0763f20ba9f847d32634953450eb7..e7dbdc2092b926243e065ccfed0e6a0ce80528c8 100644 --- a/Powers/__init__.py +++ b/Powers/__init__.py @@ -1,10 +1,10 @@ +import shutil from datetime import datetime from importlib import import_module as imp_mod from logging import (INFO, WARNING, FileHandler, StreamHandler, basicConfig, getLogger) from os import environ, listdir, mkdir, path from platform import python_version -from random import choice from sys import exit as sysexit from sys import stdout, version_info from time import time @@ -13,6 +13,7 @@ from traceback import format_exc import lyricsgenius import pyrogram import pytz +from apscheduler.schedulers.asyncio import AsyncIOScheduler LOG_DATETIME = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") LOGDIR = f"{__name__}/logs" @@ -20,6 +21,9 @@ LOGDIR = f"{__name__}/logs" # Make Logs directory if it does not exixts if not path.isdir(LOGDIR): mkdir(LOGDIR) +else: + shutil.rmtree(LOGDIR) + mkdir(LOGDIR) LOGFILE = f"{LOGDIR}/{__name__}_{LOG_DATETIME}_log.txt" @@ -47,7 +51,8 @@ if version_info[0] < 3 or version_info[1] < 7: # the secret configuration specific things try: - if environ.get("ENV"): + from Powers.vars import is_env + if is_env or environ.get("ENV"): from Powers.vars import Config else: from Powers.vars import Development as Config @@ -55,12 +60,12 @@ except Exception as ef: LOGGER.error(ef) # Print Error LOGGER.error(format_exc()) sysexit(1) -#time zone +# time zone TIME_ZONE = pytz.timezone(Config.TIME_ZONE) -path = "./Version" +Vpath = "./Version" version = [] -for i in listdir(path): +for i in listdir(Vpath): if i.startswith("version") and i.endswith("md"): version.append(i) else: @@ -92,16 +97,16 @@ if Config.GENIUS_API_TOKEN: genius_lyrics.verbose = False LOGGER.info("Client setup complete") elif not Config.GENIUS_API_TOKEN: - LOGGER.error("Genius api not found lyrics command will not work") + LOGGER.info("Genius api not found lyrics command will not work") is_genius_lyrics = False genius_lyrics = False -is_audd = False -Audd = None -if Config.AuDD_API: - is_audd = True - Audd = Config.AuDD_API - LOGGER.info("Found Audd api") +# is_audd = False +# Audd = None +# if Config.AuDD_API: +# is_audd = True +# Audd = Config.AuDD_API +# LOGGER.info("Found Audd api") is_rmbg = False RMBG = None @@ -114,25 +119,15 @@ API_ID = Config.API_ID API_HASH = Config.API_HASH # General Config -MESSAGE_DUMP = Config.MESSAGE_DUMP +MESSAGE_DUMP = Config.MESSAGE_DUMP if Config.MESSAGE_DUMP else Config.OWNER_ID SUPPORT_GROUP = Config.SUPPORT_GROUP SUPPORT_CHANNEL = Config.SUPPORT_CHANNEL -# Users Config +# Users Config OWNER_ID = Config.OWNER_ID -DEV = Config.DEV_USERS -DEVS_USER = set(DEV) -SUDO_USERS = Config.SUDO_USERS -WHITELIST_USERS = Config.WHITELIST_USERS - - - -defult_dev = [1344569458, 1432756163, 5294360309] + [int(OWNER_ID)] - -Defult_dev = set(defult_dev) - -DEVS = DEVS_USER | Defult_dev -DEV_USERS = list(DEVS) +DEV_USERS = set(Config.DEV_USERS) +SUDO_USERS = set(Config.SUDO_USERS) +WHITELIST_USERS = set(Config.WHITELIST_USERS) # Plugins, DB and Workers DB_URI = Config.DB_URI @@ -147,16 +142,31 @@ PREFIX_HANDLER = Config.PREFIX_HANDLER HELP_COMMANDS = {} # For help menu UPTIME = time() # Check bot uptime -from apscheduler.schedulers.asyncio import AsyncIOScheduler +#Make dir +youtube_dir = "./Youtube/" +if not path.isdir(youtube_dir): + mkdir(youtube_dir) +else: + shutil.rmtree(youtube_dir) + mkdir(youtube_dir) + +scrap_dir = "./scrapped/" +if not path.isdir(scrap_dir): + mkdir(scrap_dir) +else: + shutil.rmtree(scrap_dir) + mkdir(scrap_dir) scheduler = AsyncIOScheduler(timezone=TIME_ZONE) + async def load_cmds(all_plugins): """Loads all the plugins in bot.""" for single in all_plugins: # If plugin in NO_LOAD, skip the plugin if single.lower() in [i.lower() for i in Config.NO_LOAD]: - LOGGER.warning(f"Not loading '{single}' s it's added in NO_LOAD list") + LOGGER.warning( + f"Not loading '{single}' s it's added in NO_LOAD list") continue imported_module = imp_mod(f"Powers.plugins.{single}") @@ -197,6 +207,7 @@ async def load_cmds(all_plugins): LOGGER.warning(f"Not loading Plugins - {NO_LOAD}") return ( - ", ".join((i.split(".")[1]).capitalize() for i in list(HELP_COMMANDS.keys())) + ", ".join((i.split(".")[1]).capitalize() + for i in list(HELP_COMMANDS.keys())) + "\n" ) diff --git a/Powers/__main__.py b/Powers/__main__.py index 98a7dec89f755d148c6138e838fd183260467d31..2c0616444bf58dc46dc7cbc300fc5ee574a128cc 100644 --- a/Powers/__main__.py +++ b/Powers/__main__.py @@ -1,8 +1,6 @@ -import uvloop # Comment it out if using on windows +# import uvloop # Comment it out if using on windows from Powers.bot_class import Gojo if __name__ == "__main__": - uvloop.install() # Comment it out if using on windows + # uvloop.install() # Comment it out if using on windows Gojo().run() - - diff --git a/Powers/bot_class.py b/Powers/bot_class.py index 42c5effce0c4a121b3a111e023160662e427acb5..d13b9e6160f89e37c023187599b97768492abcc5 100644 --- a/Powers/bot_class.py +++ b/Powers/bot_class.py @@ -1,6 +1,7 @@ from platform import python_version from threading import RLock -from time import gmtime, strftime, time +from time import gmtime, strftime +from time import time as t from pyrogram import Client, __version__ from pyrogram.raw.all import layer @@ -24,7 +25,6 @@ if MESSAGE_DUMP == -100 or not str(MESSAGE_DUMP).startswith("-100"): ) - class Gojo(Client): """Starts the Pyrogram Client on the Bot Token when we do 'python3 -m Powers'""" @@ -45,10 +45,11 @@ class Gojo(Client): await super().start() await self.set_bot_commands( [ - BotCommand("start", "To check weather the bot is alive or not"), + BotCommand( + "start", "To check weather the bot is alive or not"), BotCommand("help", "To get help menu"), BotCommand("donate", "To buy me a coffee"), - BotCommand("bug","To report bugs") + BotCommand("bug", "To report bugs") ] ) meh = await self.get_me() # Get bot info from pyrogram client @@ -67,10 +68,11 @@ class Gojo(Client): # Get cmds and keys cmd_list = await load_cmds(await all_plugins()) await load_support_users() + await cache_support() LOGGER.info(f"Plugins Loaded: {cmd_list}") - scheduler.add_job(clean_my_db,'cron',[self],hour=3,minute=0,second=0) if BDB_URI: - scheduler.add_job(send_wishish,'cron',[self],hour=0,minute=0,second=0) + scheduler.add_job(send_wishish, 'cron', [ + self], hour=0, minute=0, second=0) scheduler.start() # Send a message to MESSAGE_DUMP telling that the # bot has started and has loaded all plugins! @@ -87,24 +89,22 @@ class Gojo(Client): async def stop(self): """Stop the bot and send a message to MESSAGE_DUMP telling that the bot has stopped.""" - runtime = strftime("%Hh %Mm %Ss", gmtime(time() - UPTIME)) + runtime = strftime("%Hh %Mm %Ss", gmtime(t() - UPTIME)) LOGGER.info("Uploading logs before stopping...!\n") # Send Logs to MESSAGE_DUMP and LOG_CHANNEL + scheduler.remove_all_jobs() + if MESSAGE_DUMP: + # LOG_CHANNEL is not necessary + target = MESSAGE_DUMP + else: + target = OWNER_ID await self.send_document( - MESSAGE_DUMP, + target, document=LOGFILE, caption=( "Bot Stopped!\n\n" f"Uptime: {runtime}\n" f"{LOG_DATETIME}" ), ) - scheduler.remove_all_jobs() - if MESSAGE_DUMP: - # LOG_CHANNEL is not necessary - await self.send_document( - MESSAGE_DUMP, - document=LOGFILE, - caption=f"Uptime: {runtime}", - ) await super().stop() MongoDB.close() LOGGER.info( diff --git a/Powers/database/afk_db.py b/Powers/database/afk_db.py index a91a5eb764c564e511bceedd256bfcaf83e5f262..0b2baad8ea952125a75c6c762c04d1236e6bbf47 100644 --- a/Powers/database/afk_db.py +++ b/Powers/database/afk_db.py @@ -13,43 +13,45 @@ class AFK(MongoDB): def __init__(self) -> None: super().__init__(self.db_name) - def insert_afk(self, chat_id, user_id, time, reason, media_type,media=None): + def insert_afk(self, chat_id, user_id, time, reason, media_type, media=None): with INSERTION_LOCK: curr = self.check_afk(chat_id=chat_id, user_id=user_id) if curr: if reason: - self.update({"chat_id":chat_id,"user_id":user_id},{"reason":reason,"time":time}) + self.update({"chat_id": chat_id, "user_id": user_id}, { + "reason": reason, "time": time}) if media: - self.update({"chat_id":chat_id,"user_id":user_id},{'media':media,'media_type':media_type,"time":time}) + self.update({"chat_id": chat_id, "user_id": user_id}, { + 'media': media, 'media_type': media_type, "time": time}) return True else: self.insert_one( { - "chat_id":chat_id, - "user_id":user_id, - "reason":reason, - "time":time, - "media":media, - "media_type":media_type + "chat_id": chat_id, + "user_id": user_id, + "reason": reason, + "time": time, + "media": media, + "media_type": media_type } ) return True def check_afk(self, chat_id, user_id): - curr = self.find_one({"chat_id":chat_id,"user_id":user_id}) + curr = self.find_one({"chat_id": chat_id, "user_id": user_id}) if curr: return True return False - + def get_afk(self, chat_id, user_id): - curr = self.find_one({"chat_id":chat_id,"user_id":user_id}) + curr = self.find_one({"chat_id": chat_id, "user_id": user_id}) if curr: return curr return - + def delete_afk(self, chat_id, user_id): with INSERTION_LOCK: - curr = self.check_afk(chat_id,user_id) + curr = self.check_afk(chat_id, user_id) if curr: - self.delete_one({"chat_id":chat_id,"user_id":user_id}) - return \ No newline at end of file + self.delete_one({"chat_id": chat_id, "user_id": user_id}) + return diff --git a/Powers/database/antispam_db.py b/Powers/database/antispam_db.py index d90ece2337c4a1f6fdb89f5f9eb02dfc5640cb3f..67ff591c5aac5c707ed44ff8c4898dbbe16e9077 100644 --- a/Powers/database/antispam_db.py +++ b/Powers/database/antispam_db.py @@ -28,6 +28,7 @@ class GBan(MongoDB): return self.update_gban_reason(user_id, reason) # If not already gbanned, then add to gban + ANTISPAM_BANNED.add(user_id) time_rn = datetime.now(TZ) return self.insert_one( { @@ -43,8 +44,8 @@ class GBan(MongoDB): with INSERTION_LOCK: # Check if user is already gbanned or not if self.find_one({"_id": user_id}): + ANTISPAM_BANNED.remove(user_id) return self.delete_one({"_id": user_id}) - return "User not gbanned!" def get_gban(self, user_id: int): diff --git a/Powers/database/approve_db.py b/Powers/database/approve_db.py index 3cef38a3ca09120225b4533cfc67b5d505811658..899af43e4b632920cc241c648b49f9fb179a51a1 100644 --- a/Powers/database/approve_db.py +++ b/Powers/database/approve_db.py @@ -1,11 +1,16 @@ from threading import RLock + from Powers import LOGGER from Powers.database import MongoDB + INSERTION_LOCK = RLock() + + class Approve(MongoDB): """Class for managing Approves in Chats in Bot.""" # Database name to connect to to preform operations db_name = "approve" + def __init__(self, chat_id: int) -> None: super().__init__(self.db_name) self.chat_id = chat_id @@ -22,7 +27,6 @@ class Approve(MongoDB): else: j = False return j - def add_approve(self, user_id: int, user_name: str): with INSERTION_LOCK: @@ -33,6 +37,7 @@ class Approve(MongoDB): {"users": self.chat_info["users"]}, ) return True + def remove_approve(self, user_id: int): with INSERTION_LOCK: if self.check_approve(user_id): @@ -47,50 +52,59 @@ class Approve(MongoDB): {"users": self.chat_info["users"]}, ) return True + def unapprove_all(self): with INSERTION_LOCK: return self.delete_one( {"_id": self.chat_id}, ) + def clean_approve(self): with INSERTION_LOCK: return self.delete_one( - {"_id":self.chat_id} + {"_id": self.chat_id} ) + def list_approved(self): with INSERTION_LOCK: return self.chat_info["users"] + def count_approved(self): with INSERTION_LOCK: return len(self.chat_info["users"]) + def load_from_db(self): return self.find_all() + def __ensure_in_db(self): chat_data = self.find_one({"_id": self.chat_id}) if not chat_data: new_data = {"_id": self.chat_id, "users": []} self.insert_one(new_data) - LOGGER.info(f"Initialized Approve Document for chat {self.chat_id}") return new_data return chat_data # Migrate if chat id changes! + def migrate_chat(self, new_chat_id: int): old_chat_db = self.find_one({"_id": self.chat_id}) new_data = old_chat_db.update({"_id": new_chat_id}) self.insert_one(new_data) self.delete_one({"_id": self.chat_id}) + @staticmethod def count_all_approved(): with INSERTION_LOCK: collection = MongoDB(Approve.db_name) all_data = collection.find_all() return sum(len(i["users"]) for i in all_data if len(i["users"]) >= 1) + @staticmethod def count_approved_chats(): with INSERTION_LOCK: collection = MongoDB(Approve.db_name) all_data = collection.find_all() return sum(len(i["users"]) >= 1 for i in all_data) + @staticmethod def repair_db(collection): all_data = collection.find_all() diff --git a/Powers/database/autojoin_db.py b/Powers/database/autojoin_db.py index 3328e1f544753ce617b0b33d9063b0194fb88f55..3bff8a50745e9a99d05a218598cee907b5b98b4e 100644 --- a/Powers/database/autojoin_db.py +++ b/Powers/database/autojoin_db.py @@ -15,36 +15,36 @@ class AUTOJOIN(MongoDB): def __init__(self) -> None: super().__init__(self.db_name) - def load_autojoin(self, chat,mode="auto"): + def load_autojoin(self, chat, mode="auto"): """ type = auto or notify auto to auto accept join requests notify to notify the admins about the join requests """ - curr = self.find_one({"chat_id":chat,}) + curr = self.find_one({"chat_id": chat, }) if not curr: with INSERTION_LOCK: - self.insert_one({"chat_id":chat,"type":mode}) + self.insert_one({"chat_id": chat, "type": mode}) return True return False - def get_autojoin(self,chat): - curr = self.find_one({"chat_id":chat}) + def get_autojoin(self, chat): + curr = self.find_one({"chat_id": chat}) if not curr: return False else: return curr["type"] - def update_join_type(self,chat,mode): - curr = self.find_one({"chat_id":chat}) + def update_join_type(self, chat, mode): + curr = self.find_one({"chat_id": chat}) if curr: - self.update({"chat_id":chat},{"type":mode}) - return + self.update({"chat_id": chat}, {"type": mode}) + return else: return - def remove_autojoin(self,chat): - curr = self.find_one({"chat_id":chat}) + def remove_autojoin(self, chat): + curr = self.find_one({"chat_id": chat}) if curr: - self.delete_one({"chat_id":chat}) - return \ No newline at end of file + self.delete_one({"chat_id": chat}) + return diff --git a/Powers/database/blacklist_db.py b/Powers/database/blacklist_db.py index 0e7a5bdf6837d2b7e5439e1eb6c97f73fd24d806..7252ae288b6a5193936171c03007d68b078bb5c2 100644 --- a/Powers/database/blacklist_db.py +++ b/Powers/database/blacklist_db.py @@ -110,13 +110,12 @@ class Blacklist(MongoDB): "reason": "Automated blacklisted word: {{}}", } self.insert_one(new_data) - LOGGER.info(f"Initialized Blacklist Document for chat {self.chat_id}") return new_data return chat_data def clean_blacklist(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) # Migrate if chat id changes! def migrate_chat(self, new_chat_id: int): diff --git a/Powers/database/captcha_db.py b/Powers/database/captcha_db.py index 8c55563ce2c34515b92e1faf44f5bc45698ad0bf..34d41a69b9192b37b542a4a71b7f488c71c7c4c8 100644 --- a/Powers/database/captcha_db.py +++ b/Powers/database/captcha_db.py @@ -13,15 +13,15 @@ class CAPTCHA(MongoDB): def __init__(self) -> None: super().__init__(self.db_name) - def insert_captcha(self, chat, captcha_type:str="qr", captcha_action:str = "mute"): + def insert_captcha(self, chat, captcha_type: str = "qr", captcha_action: str = "mute"): with INSERTION_LOCK: curr = self.is_captcha(chat) if not curr: self.insert_one( { - "chat_id":chat, - "captcha_type":captcha_type, - "captcha_action":captcha_action + "chat_id": chat, + "captcha_type": captcha_type, + "captcha_action": captcha_action } ) return @@ -36,29 +36,31 @@ class CAPTCHA(MongoDB): with INSERTION_LOCK: curr = self.is_captcha(chat) if curr: - self.update({"chat_id":chat},{"captcha_type":captcha_type}) + self.update({"chat_id": chat}, {"captcha_type": captcha_type}) return def update_action(self, chat, captcha_action): with INSERTION_LOCK: curr = self.is_captcha(chat) if curr: - self.update({"chat_id":chat},{"captcha_action":captcha_action}) + self.update({"chat_id": chat}, { + "captcha_action": captcha_action}) return - + def remove_captcha(self, chat): with INSERTION_LOCK: curr = self.is_captcha(chat) if curr: - self.delete_one({"chat_id":chat}) + self.delete_one({"chat_id": chat}) return def get_captcha(self, chat): - curr = self.find_one({"chat_id":chat}) + curr = self.find_one({"chat_id": chat}) if curr: return curr return False + class CAPTCHA_DATA(MongoDB): """class to store captcha data""" db_name = "captcha_data" @@ -67,47 +69,57 @@ class CAPTCHA_DATA(MongoDB): super().__init__(self.db_name) def load_cap_data(self, chat, user, data): - curr = self.find_one({"chat_id":chat,"user_id":user}) + curr = self.find_one({"chat_id": chat, "user_id": user}) if not curr: with INSERTION_LOCK: - self.insert_one({"chat_id":chat,"user_id":user,"data":data}) + self.insert_one( + {"chat_id": chat, "user_id": user, "data": data}) return True else: return def get_cap_data(self, chat, user): - curr = self.find_one({"chat_id":chat,"user_id":user}) + curr = self.find_one({"chat_id": chat, "user_id": user}) if curr: return curr["data"] else: return False def remove_cap_data(self, chat, user): - curr = self.find_one({"chat_id":chat,"user_id":user}) + curr = self.find_one({"chat_id": chat, "user_id": user}) if curr: with INSERTION_LOCK: - self.delete_one({"chat_id":chat,"user_id":user}) + self.delete_one({"chat_id": chat, "user_id": user}) return def store_message_id(self, chat, user, message): - curr = self.find_one({"chat_id":chat,"user_id":user}) + curr = self.find_one({"chat_id": chat, "user_id": user}) if not curr: with INSERTION_LOCK: - self.insert_one({"chat_id":chat,"user_id":user,"message_id":message}) + self.insert_one( + {"chat_id": chat, "user_id": user, "message_id": message}) return else: - return - - def is_already_data(self, chat, user): - curr = self.find_one({"chat_id":chat,"user_id":user}) + return + + def get_message_id(self, chat, user): + curr = self.find_one({"chat_id": chat, "user_id": user}) if curr: return curr["message_id"] else: return False + def is_already_data(self, chat, user): + curr = self.find_one({"chat_id": chat, "user_id": user}) + if curr: + return curr.get("message_id", False) + else: + return False + def del_message_id(self, chat, user): - curr = self.find_one({"chat_id":chat,"user_id":user}) + curr = self.find_one({"chat_id": chat, "user_id": user}) if curr: with INSERTION_LOCK: - self.delete_one({"chat_id":chat,"user_id":user}) - return \ No newline at end of file + self.delete_one({"chat_id": chat, "user_id": user}) + + return curr["message_id"] \ No newline at end of file diff --git a/Powers/database/chats_db.py b/Powers/database/chats_db.py index b4029a4141fc2a62ca1cac9777e27c5159664ae1..e580f7ffc3ca213f91160edc5e38c3115c33f732 100644 --- a/Powers/database/chats_db.py +++ b/Powers/database/chats_db.py @@ -107,7 +107,6 @@ class Chats(MongoDB): if not chat_data: new_data = {"_id": self.chat_id, "chat_name": "", "users": []} self.insert_one(new_data) - LOGGER.info(f"Initialized Chats Document for chat {self.chat_id}") return new_data return chat_data diff --git a/Powers/database/disable_db.py b/Powers/database/disable_db.py index fb425f8a2473d2c05c473b834a43071b0436ea5e..6f821b78a5d7009eeb4b08ed4901564218fe35b7 100644 --- a/Powers/database/disable_db.py +++ b/Powers/database/disable_db.py @@ -146,9 +146,9 @@ class Disabling(MongoDB): "commands": [], "action": "none", } - DISABLED_CMDS[self.chat_id] = {"commands": [], "action": "none"} + DISABLED_CMDS[self.chat_id] = { + "commands": [], "action": "none"} self.insert_one(new_data) - LOGGER.info(f"Initialized Disabling Document for chat {self.chat_id}") return new_data DISABLED_CMDS[self.chat_id] = chat_data return chat_data @@ -163,7 +163,7 @@ class Disabling(MongoDB): def clean_disable(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) @staticmethod def repair_db(collection): diff --git a/Powers/database/filters_db.py b/Powers/database/filters_db.py index d3fda53d9daeb4ae9f8a07953fbb9f97879dc742..3172a62eeb71ae3d9cd9a3c66db79e65731b053e 100644 --- a/Powers/database/filters_db.py +++ b/Powers/database/filters_db.py @@ -24,7 +24,15 @@ class Filters(MongoDB): # Database update curr = self.find_one({"chat_id": chat_id, "keyword": keyword}) if curr: - return False + self.update( + {"chat_id": chat_id, "keyword": keyword}, + { + "filter_reply": filter_reply, + "msgtype": msgtype, + "fileid": fileid + } + ) + return return self.insert_one( { "chat_id": chat_id, @@ -71,7 +79,8 @@ class Filters(MongoDB): curr = self.find_all() if curr: return len( - [z for z in (i["keyword"].split("|") for i in curr) if len(z) >= 2], + [z for z in (i["keyword"].split("|") + for i in curr) if len(z) >= 2], ) return 0 diff --git a/Powers/database/flood_db.py b/Powers/database/flood_db.py index c29fe9f07e09154438fc20cb1e59688392df5f43..99528ec3b21edeb1a2688998f798fe85e8d23bbc 100644 --- a/Powers/database/flood_db.py +++ b/Powers/database/flood_db.py @@ -7,6 +7,7 @@ from Powers.utils.msg_types import Types INSERTION_LOCK = RLock() + class Floods(MongoDB): """Class to store flood limit and action of a chat""" db_name = "flood" @@ -24,7 +25,7 @@ class Floods(MongoDB): with INSERTION_LOCK: curr = self.find_one({"chat_id": chat_id}) if curr: - if not(limit == int(curr['limit']) and within == int(curr['within']) and action == str(curr['action'])): + if not (limit == int(curr['limit']) and within == int(curr['within']) and action == str(curr['action'])): return self.update( { "chat_id": chat_id @@ -36,37 +37,37 @@ class Floods(MongoDB): } ) else: - return + return else: return self.insert_one( { - "chat_id" : chat_id, + "chat_id": chat_id, "limit": limit, "within": within, - "action" : action + "action": action }, ) - + def is_chat(self, chat_id: int): with INSERTION_LOCK: curr = self.find_one({"chat_id": chat_id}) if curr: - action = [str(curr['limit']), str(curr['within']), str(curr['action'])] + action = [str(curr['limit']), str( + curr['within']), str(curr['action'])] return action return False - + def get_action(self, chat_id: int): with INSERTION_LOCK: curr = self.find_one({"chat_id": chat_id}) if curr: return curr['action'] return "Flood haven't set" - + def rm_flood(self, chat_id: int): with INSERTION_LOCK: curr = self.find_one({"chat_id": chat_id}) if curr: - self.delete_one({"chat_id":chat_id}) + self.delete_one({"chat_id": chat_id}) return True return False - \ No newline at end of file diff --git a/Powers/database/greetings_db.py b/Powers/database/greetings_db.py index 29165b79d0e49174be8428b917f5c049a4769d8f..3a00e44505369c2dc9a018f722fa403442d1ed52 100644 --- a/Powers/database/greetings_db.py +++ b/Powers/database/greetings_db.py @@ -45,6 +45,7 @@ class Greetings(MongoDB): def get_welcome_media(self): with INSERTION_LOCK: return self.chat_info["welcome_media"] + def get_welcome_msgtype(self): with INSERTION_LOCK: return self.chat_info["welcome_mtype"] @@ -78,32 +79,32 @@ class Greetings(MongoDB): with INSERTION_LOCK: return self.update({"_id": self.chat_id}, {"goodbye": status}) - def set_welcome_text(self, welcome_text: str, mtype,media=None): + def set_welcome_text(self, welcome_text: str, mtype, media=None): with INSERTION_LOCK: self.update( {"_id": self.chat_id}, - {"welcome_text": welcome_text,"welcome_mtype":mtype}, + {"welcome_text": welcome_text, "welcome_mtype": mtype}, ) if media: self.update( {"_id": self.chat_id}, - {"welcome_media": media,"welcome_mtype":mtype} + {"welcome_media": media, "welcome_mtype": mtype} ) - return + return - def set_goodbye_text(self, goodbye_text: str,mtype,media=None): + def set_goodbye_text(self, goodbye_text: str, mtype, media=None): with INSERTION_LOCK: self.update( {"_id": self.chat_id}, - {"goodbye_text": goodbye_text,"goodbye_mtype":mtype}, + {"goodbye_text": goodbye_text, "goodbye_mtype": mtype}, ) if media: self.update( {"_id": self.chat_id}, - {"goodbye_media": media,"goodbye_mtype":mtype} + {"goodbye_media": media, "goodbye_mtype": mtype} ) - return + return def set_current_cleanservice_settings(self, status: bool): with INSERTION_LOCK: @@ -154,13 +155,12 @@ class Greetings(MongoDB): "welcome_text": "Hey {first}, welcome to {chatname}!", "welcome": True, "goodbye": True, - "welcome_media":False, - "welcome_mtype":False, - "goodbye_media":False, - "goodbye_mtype":False + "welcome_media": False, + "welcome_mtype": False, + "goodbye_media": False, + "goodbye_mtype": False } self.insert_one(new_data) - LOGGER.info(f"Initialized Greetings Document for chat {self.chat_id}") return new_data return chat_data @@ -173,7 +173,7 @@ class Greetings(MongoDB): def clean_greetings(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) @staticmethod def count_chats(query: str): diff --git a/Powers/database/locks_db.py b/Powers/database/locks_db.py index c301e189e5db1a1a1b3f831d344f0829960673e5..222ecbc098e8316020c9a258c378fb986f964abc 100644 --- a/Powers/database/locks_db.py +++ b/Powers/database/locks_db.py @@ -5,9 +5,13 @@ from Powers.database import MongoDB INSERTION_LOCK = RLock() +lock_t = ["bot", "anti_c_send", "anti_fwd", + "anti_fwd_u", "anti_fwd_c", "anti_links"] + + class LOCKS(MongoDB): """Class to store locks""" - + db_name = "locks" def __init__(self) -> None: @@ -15,59 +19,98 @@ class LOCKS(MongoDB): def insert_lock_channel(self, chat: int, locktype: str): """ - locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + locktypes: all, bot, anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links """ - curr = self.find_one({"chat_id":chat,"locktype":locktype}) + if locktype == "all": + for i in lock_t: + curr = self.find_one({"chat_id": chat, "locktype": i}) + if curr: + continue + if i in ["anti_fwd_u", "anti_fwd_c"]: + continue + self.insert_one({"chat_id": chat, "locktype": i}) + return True + curr = self.find_one({"chat_id": chat, "locktype": locktype}) if curr: return False else: with INSERTION_LOCK: - hmm = self.merge_u_and_c(chat,locktype) + hmm = self.merge_u_and_c(chat, locktype) if not hmm: - self.insert_one({"chat_id":chat,"locktype":locktype}) + self.insert_one({"chat_id": chat, "locktype": locktype}) return True def remove_lock_channel(self, chat: int, locktype: str): """ - locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + locktypes: all, bot, anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links """ - curr = self.find_one({"chat_id":chat,"locktype":locktype}) + if locktype == "all": + for i in lock_t: + curr = self.find_one({"chat_id": chat, "locktype": i}) + if curr: + self.delete_one({"chat_id": chat, "locktype": i}) + return True + curr = self.find_one({"chat_id": chat, "locktype": locktype}) if curr: with INSERTION_LOCK: - self.delete_one({"chat_id":chat,"locktype":locktype}) + self.delete_one({"chat_id": chat, "locktype": locktype}) return True else: return False - def get_lock_channel(self, locktype: str="all"): + def get_lock_channel(self, chat: int, locktype: str = "all"): """ - locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links, bot """ - if locktype not in ["anti_c_send","anti_fwd","anti_fwd_u","anti_fwd_c","anti_links", "all"]: + if locktype not in ["anti_c_send", "anti_fwd", "anti_fwd_u", "anti_fwd_c", "anti_links", "bot", "all"]: return False else: - if locktype == "all": - find = {} - else: - find = {"locktype":locktype} - curr = self.find_all(find) - if not curr: - list_ = [] + if locktype != "all": + curr = self.find_one( + {"chat_id": chat, "locktype": locktype}) + return bool(curr) else: - list_ = [i["chat_id"] for i in curr] - return list_ + to_return = { + "anti_channel": False, + "anti_fwd": { + "user": False, + "chat": False + }, + "anti_links": False, + "bot": False + } + curr = self.find_all({"chat_id": chat}) + if not curr: + return None + else: + for i in list(curr): + if i["locktype"] == "anti_c_send": + to_return["anti_channel"] = True + elif i["locktype"] == "anti_fwd": + to_return["anti_fwd"]["user"] = to_return["anti_fwd"]["chat"] = True + elif i["locktype"] == "anti_fwd_u": + to_return["anti_fwd"]["user"] = True + elif i["locktype"] == "anti_fwd_c": + to_return["anti_fwd"]["chat"] = True + elif i["anti_links"] == "anti_links": + to_return["anti_links"] = True + elif i["locktype"] == "bot": + to_return["bot"] = True + else: + continue + return to_return def merge_u_and_c(self, chat: int, locktype: str): if locktype == "anti_fwd_u": - curr = self.find_one({"chat_id":chat,"locktype":"anti_fwd_c"}) + curr = self.find_one({"chat_id": chat, "locktype": "anti_fwd_c"}) elif locktype == "anti_fwd_c": - curr = self.find_one({"chat_id":chat,"locktype":"anti_fwd_u"}) + curr = self.find_one({"chat_id": chat, "locktype": "anti_fwd_u"}) else: return False if curr: - self.delete_one({"chat_id":chat,"locktype":locktype}) - self.insert_one({"chat_id":chat,"locktype":"anti_fwd"}) + self.delete_one({"chat_id": chat, "locktype": locktype}) + self.insert_one({"chat_id": chat, "locktype": "anti_fwd"}) return True else: return False @@ -76,9 +119,8 @@ class LOCKS(MongoDB): """ locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links """ - curr = self.find_one({"chat_id":chat,"locktype":locktype}) + curr = self.find_one({"chat_id": chat, "locktype": locktype}) if curr: return True else: return False - \ No newline at end of file diff --git a/Powers/database/notes_db.py b/Powers/database/notes_db.py index 1b460c79da8b4b5f4c2c80b527c10d9677abf872..ad8b757067f9b8a8424de0b24787c4cca72ac101 100644 --- a/Powers/database/notes_db.py +++ b/Powers/database/notes_db.py @@ -57,7 +57,8 @@ class Notes(MongoDB): def get_all_notes(self, chat_id: int): with INSERTION_LOCK: curr = self.find_all({"chat_id": chat_id}) - note_list = sorted([(note["note_name"], note["hash"]) for note in curr]) + note_list = sorted([(note["note_name"], note["hash"]) + for note in curr]) return note_list def rm_note(self, chat_id: int, note_name: str): @@ -124,9 +125,9 @@ class NotesSettings(MongoDB): self.update({"_id": chat_id}, {"privatenotes": False}) return False - def clean_notes(self,chat_id): + def clean_notes(self, chat_id): with INSERTION_LOCK: - return self.delete_one({"_id":chat_id}) + return self.delete_one({"_id": chat_id}) def list_chats(self): return self.find_all({"privatenotes": True}) diff --git a/Powers/database/pins_db.py b/Powers/database/pins_db.py index 7c8882a347e1d0a1c942f5ac68ceec2a28cf9497..20644a9c96045d82732ef5b661c6f3d98a5dc744 100644 --- a/Powers/database/pins_db.py +++ b/Powers/database/pins_db.py @@ -62,13 +62,12 @@ class Pins(MongoDB): "cleanlinked": False, } self.insert_one(new_data) - LOGGER.info(f"Initialized Pins Document for chat {self.chat_id}") return new_data return chat_data def clean_pins(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) # Migrate if chat id changes! def migrate_chat(self, new_chat_id: int): diff --git a/Powers/database/reporting_db.py b/Powers/database/reporting_db.py index 935c6e35353aadbc1ec2801c1f39d14072e14c16..9b9f1e7dfc96a8c2c9aec6eae5a7b2b16f9779ef 100644 --- a/Powers/database/reporting_db.py +++ b/Powers/database/reporting_db.py @@ -42,9 +42,9 @@ class Reporting(MongoDB): chat_data = self.find_one({"_id": self.chat_id}) if not chat_data: chat_type = self.get_chat_type() - new_data = {"_id": self.chat_id, "status": True, "chat_type": chat_type} + new_data = {"_id": self.chat_id, + "status": True, "chat_type": chat_type} self.insert_one(new_data) - LOGGER.info(f"Initialized Language Document for chat {self.chat_id}") return new_data return chat_data @@ -57,7 +57,7 @@ class Reporting(MongoDB): def clean_reporting(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) @staticmethod def repair_db(collection): diff --git a/Powers/database/rules_db.py b/Powers/database/rules_db.py index 3e82a247cf597c0f7b52c925e1f1fbc5096faa89..4f0790cdd7f7e837e37252ca5d0a8e14aa5a2ae8 100644 --- a/Powers/database/rules_db.py +++ b/Powers/database/rules_db.py @@ -68,7 +68,6 @@ class Rules(MongoDB): if not chat_data: new_data = {"_id": self.chat_id, "privrules": False, "rules": ""} self.insert_one(new_data) - LOGGER.info(f"Initialized Language Document for chat {self.chat_id}") return new_data return chat_data diff --git a/Powers/database/support_db.py b/Powers/database/support_db.py index 70f935c15d21408672fda602391ed588ece047f5..35148c81813fa9c67a1941b20c0faba5c9748e84 100644 --- a/Powers/database/support_db.py +++ b/Powers/database/support_db.py @@ -5,6 +5,7 @@ from Powers.database import MongoDB INSERTION_LOCK = RLock() + class SUPPORTS(MongoDB): """ class to store support users in database @@ -12,7 +13,7 @@ class SUPPORTS(MongoDB): """ db_name = "supports" - + def __init__(self) -> None: super().__init__(self.db_name) @@ -22,49 +23,48 @@ class SUPPORTS(MongoDB): with INSERTION_LOCK: self.insert_one( { - "user_id":user_id, - "support_type":support_type + "user_id": user_id, + "support_type": support_type } ) return - def update_support_user_type(self,user,new_type): + def update_support_user_type(self, user, new_type): curr = self.is_support_user(user) if curr: with INSERTION_LOCK: self.update( { - "user_id":user + "user_id": user }, { - "support_type":new_type + "support_type": new_type } ) return - def is_support_user(self, user_id): - curr = self.find_one({"user_id":user_id}) + curr = self.find_one({"user_id": user_id}) if curr: return True return False - def delete_support_user(self,user): + def delete_support_user(self, user): curr = self.is_support_user(user) if curr: with INSERTION_LOCK: - self.delete_one({"user_id":user}) + self.delete_one({"user_id": user}) return - def get_particular_support(self,support_type): - curr = self.find_all({"support_type":support_type}) + def get_particular_support(self, support_type): + curr = self.find_all({"support_type": support_type}) if curr: return [i['user_id'] for i in curr] else: return [] - def get_support_type(self,user): - curr = self.find_one({"user_id":user}) + def get_support_type(self, user): + curr = self.find_one({"user_id": user}) if curr: return curr["support_type"] - return False \ No newline at end of file + return False diff --git a/Powers/database/users_db.py b/Powers/database/users_db.py index 08d9f16d42e54323dfb03db8a1821c0ac7c8af12..4a194fe3185e8a5bb03360341e85016bdb21f9cc 100644 --- a/Powers/database/users_db.py +++ b/Powers/database/users_db.py @@ -67,9 +67,9 @@ class Users(MongoDB): def __ensure_in_db(self): chat_data = self.find_one({"_id": self.user_id}) if not chat_data: - new_data = {"_id": self.user_id, "username": "", "name": "unknown_till_now"} + new_data = {"_id": self.user_id, + "username": "", "name": "unknown_till_now"} self.insert_one(new_data) - LOGGER.info(f"Initialized User Document for {self.user_id}") return new_data return chat_data diff --git a/Powers/database/warns_db.py b/Powers/database/warns_db.py index 95d4de6c7558b128c2f7bebe481e6a4e562643c1..c7117db76b2cce844a20e00e2edbc04c14d4add2 100644 --- a/Powers/database/warns_db.py +++ b/Powers/database/warns_db.py @@ -49,7 +49,7 @@ class Warns(MongoDB): def clean_warn(self): with INSERTION_LOCK: - return self.delete_one({"chat_id":self.chat_id}) + return self.delete_one({"chat_id": self.chat_id}) def get_warns(self, user_id: int): with INSERTION_LOCK: @@ -93,12 +93,14 @@ class Warns(MongoDB): f"Repairing Approve Database - setting '{key}:{val}' for {data['user_id']} in {data['chat_id']}", ) collection.update( - {"chat_id": data["chat_id"], "user_id": data["user_id"]}, + {"chat_id": data["chat_id"], + "user_id": data["user_id"]}, {key: val}, ) def __ensure_in_db(self, user_id: int): - chat_data = self.find_one({"chat_id": self.chat_id, "user_id": user_id}) + chat_data = self.find_one( + {"chat_id": self.chat_id, "user_id": user_id}) if not chat_data: new_data = { "chat_id": self.chat_id, @@ -107,7 +109,6 @@ class Warns(MongoDB): "num_warns": 0, } self.insert_one(new_data) - LOGGER.info(f"Initialized Warn Document for {user_id} in {self.chat_id}") return new_data return chat_data @@ -123,9 +124,9 @@ class WarnSettings(MongoDB): def __ensure_in_db(self): chat_data = self.find_one({"_id": self.chat_id}) if not chat_data: - new_data = {"_id": self.chat_id, "warn_mode": "none", "warn_limit": 3} + new_data = {"_id": self.chat_id, + "warn_mode": "none", "warn_limit": 3} self.insert_one(new_data) - LOGGER.info(f"Initialized Warn Settings Document for {self.chat_id}") return new_data return chat_data @@ -140,7 +141,7 @@ class WarnSettings(MongoDB): def clean_warns(self): with INSERTION_LOCK: - return self.delete_one({"_id":self.chat_id}) + return self.delete_one({"_id": self.chat_id}) def get_warnmode(self): with INSERTION_LOCK: diff --git a/Powers/plugins/__init__.py b/Powers/plugins/__init__.py index cd4ed62e4e9fd42f772f351ef8d9f85a05554b95..aa74eba62fe2fd143b067f7944d3f6b9dfff3f82 100644 --- a/Powers/plugins/__init__.py +++ b/Powers/plugins/__init__.py @@ -38,3 +38,4 @@ def till_date(date): form = "%Y-%m-%d %H:%M:%S" z = datetime.strptime(date,form) return z + diff --git a/Powers/plugins/admin.py b/Powers/plugins/admin.py index 1268a09423a7c50577d819c3a03b712dac2966e4..a28b925bcd6d4d3dac9d6345faa5edb3d96ba91f 100644 --- a/Powers/plugins/admin.py +++ b/Powers/plugins/admin.py @@ -6,26 +6,21 @@ from traceback import format_exc from pyrogram import filters from pyrogram.enums import ChatMemberStatus as CMS from pyrogram.enums import ChatType -from pyrogram.errors import (ChatAdminInviteRequired, ChatAdminRequired, - FloodWait, RightForbidden, RPCError, - UserAdminInvalid) +from pyrogram.errors import (BotChannelsNa, ChatAdminInviteRequired, + ChatAdminRequired, FloodWait, RightForbidden, + RPCError, UserAdminInvalid) from pyrogram.types import ChatPrivileges, Message -from Powers import LOGGER, OWNER_ID +from Powers import DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo from Powers.database.approve_db import Approve from Powers.database.reporting_db import Reporting -from Powers.supports import get_support_staff from Powers.utils.caching import (ADMIN_CACHE, TEMP_ADMIN_CACHE_BLOCK, admin_cache_reload) -from Powers.utils.custom_filters import (admin_filter, command, owner_filter, - promote_filter) +from Powers.utils.custom_filters import admin_filter, command, promote_filter from Powers.utils.extract_user import extract_user from Powers.utils.parser import mention_html -from Powers.vars import Config -SUPPORT_STAFF = get_support_staff() -DEV_LEVEL = get_support_staff("dev_level") @Gojo.on_message(command("adminlist")) async def adminlist_show(_, m: Message): @@ -69,7 +64,7 @@ async def adminlist_show(_, m: Message): adminstr += "\n\nBots:\n" adminstr += "\n".join(f"- {i}" for i in mention_bots) await m.reply_text(adminstr + "\n\n" + note) - LOGGER.info(f"Adminlist cmd use in {m.chat.id} by {m.from_user.id}") + except Exception as ef: if str(ef) == str(m.chat.id): await m.reply_text(text="Use /admincache to reload admins!") @@ -83,25 +78,31 @@ async def adminlist_show(_, m: Message): return + @Gojo.on_message(command("zombies") & admin_filter) async def zombie_clean(c: Gojo, m: Message): zombie = 0 wait = await m.reply_text("Searching ... and banning ...") + failed = 0 async for member in c.get_chat_members(m.chat.id): if member.user.is_deleted: zombie += 1 try: await c.ban_chat_member(m.chat.id, member.user.id) except UserAdminInvalid: - zombie -= 1 + failed += 1 except FloodWait as e: - await sleep(e.x) + await sleep(e.value) + try: + await c.ban_chat_member(m.chat.id, member.user.id) + except: + pass if zombie == 0: return await wait.edit_text("Group is clean!") - return await wait.edit_text( - text=f"{zombie} Zombies found and has been banned!", - ) - + await wait.delete() + txt=f"{zombie} Zombies found and {zombie - failed} has been banned!\n{failed} zombies' are immune to me", + await m.reply_animation("https://graph.org/file/02a1dcf7788186ffb36cb.mp4", caption=txt) + return @Gojo.on_message(command("admincache")) async def reload_admins(_, m: Message): @@ -110,6 +111,7 @@ async def reload_admins(_, m: Message): return await m.reply_text( "This command is made to be used in groups only!", ) + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if ( (m.chat.id in set(TEMP_ADMIN_CACHE_BLOCK.keys())) and (m.from_user.id not in SUPPORT_STAFF) @@ -121,7 +123,6 @@ async def reload_admins(_, m: Message): await admin_cache_reload(m, "admincache") TEMP_ADMIN_CACHE_BLOCK[m.chat.id] = "manualblock" await m.reply_text(text="Reloaded all admins in this chat!") - LOGGER.info(f"Admincache cmd use in {m.chat.id} by {m.from_user.id}") except RPCError as ef: await m.reply_text( text=f"Some error occured, report it using `/bug` \n Error: {ef}" @@ -164,8 +165,8 @@ async def fullpromote_usr(c: Gojo, m: Message): user_id, user_first_name, user_name = await extract_user(c, m) except Exception: return - bot = await c.get_chat_member(m.chat.id, Config.BOT_ID) - if user_id == Config.BOT_ID: + bot = await c.get_chat_member(m.chat.id, c.me.id) + if user_id == c.me.id: await m.reply_text("Huh, how can I even promote myself?") return if not bot.privileges.can_promote_members: @@ -205,9 +206,6 @@ async def fullpromote_usr(c: Gojo, m: Message): except Exception as e: LOGGER.error(e) LOGGER.error(format_exc()) - LOGGER.info( - f"{m.from_user.id} fullpromoted {user_id} in {m.chat.id} with title '{title}'", - ) await m.reply_text( ( "{promoter} promoted {promoted} in chat {chat_title} with full rights!" @@ -260,8 +258,8 @@ async def promote_usr(c: Gojo, m: Message): user_id, user_first_name, user_name = await extract_user(c, m) except Exception: return - bot = await c.get_chat_member(m.chat.id, Config.BOT_ID) - if user_id == Config.BOT_ID: + bot = await c.get_chat_member(m.chat.id, c.me.id) + if user_id == c.me.id: await m.reply_text("Huh, how can I even promote myself?") return if not bot.privileges.can_promote_members: @@ -291,6 +289,8 @@ async def promote_usr(c: Gojo, m: Message): can_pin_messages=bot.privileges.can_pin_messages, can_manage_chat=bot.privileges.can_manage_chat, can_manage_video_chats=bot.privileges.can_manage_video_chats, + can_post_messages=bot.privileges.can_post_messages, + can_edit_messages=bot.privileges.can_edit_messages ), ) title = "" @@ -308,9 +308,7 @@ async def promote_usr(c: Gojo, m: Message): except Exception as e: LOGGER.error(e) LOGGER.error(format_exc()) - LOGGER.info( - f"{m.from_user.id} promoted {user_id} in {m.chat.id} with title '{title}'", - ) + await m.reply_text( ("{promoter} promoted {promoted} in chat {chat_title}!").format( promoter=(await mention_html(m.from_user.first_name, m.from_user.id)), @@ -359,7 +357,7 @@ async def demote_usr(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) except Exception: return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Get an admin to demote me!") return # If user not already admin @@ -379,7 +377,6 @@ async def demote_usr(c: Gojo, m: Message): user_id=user_id, privileges=ChatPrivileges(can_manage_chat=False), ) - LOGGER.info(f"{m.from_user.id} demoted {user_id} in {m.chat.id}") # ----- Remove admin from cache ----- try: admin_list = ADMIN_CACHE[m.chat.id] @@ -408,6 +405,8 @@ async def demote_usr(c: Gojo, m: Message): await m.reply_text( "Cannot act on this user, maybe I wasn't the one who changed their permissions." ) + except BotChannelsNa: + await m.reply_text("May be the user is bot and due to telegram restrictions I can't demote them. Please do it manually") except RPCError as ef: await m.reply_text( f"Some error occured, report it using `/bug` \n Error: {ef}" @@ -420,6 +419,8 @@ async def demote_usr(c: Gojo, m: Message): @Gojo.on_message(command("invitelink")) async def get_invitelink(c: Gojo, m: Message): # Bypass the bot devs, sudos and owner + + DEV_LEVEL = DEV_USERS if m.from_user.id not in DEV_LEVEL: user = await m.chat.get_member(m.from_user.id) if not user.privileges.can_invite_users and user.status != CMS.OWNER: @@ -431,7 +432,6 @@ async def get_invitelink(c: Gojo, m: Message): text=f"Invite Link for Chat {m.chat.id}: {link}", disable_web_page_preview=True, ) - LOGGER.info(f"{m.from_user.id} exported invite link in {m.chat.id}") except ChatAdminRequired: await m.reply_text(text="I'm not admin or I don't have rights.") except ChatAdminInviteRequired: @@ -508,7 +508,7 @@ async def set_user_title(c: Gojo, m: Message): return if not user_id: return await m.reply_text("Cannot find user!") - if user_id == Config.BOT_ID: + if user_id == c.me.id: return await m.reply_text("Huh, why ?") if not reason: return await m.reply_text("Read /help please!") diff --git a/Powers/plugins/afk.py b/Powers/plugins/afk.py new file mode 100644 index 0000000000000000000000000000000000000000..58bced21298ab116d036355ad3ab10363a2095e6 --- /dev/null +++ b/Powers/plugins/afk.py @@ -0,0 +1,158 @@ +from datetime import datetime +from random import choice + +from pyrogram import ContinuePropagation, filters +from pyrogram.enums import ParseMode as PM +from pyrogram.types import Message + +from Powers.bot_class import Gojo +from Powers.database.afk_db import AFK +from Powers.plugins import till_date +from Powers.utils.cmd_senders import send_cmd +from Powers.utils.custom_filters import afk_filter, command +from Powers.utils.msg_types import Types, get_afk_type + +res = [ + "{first} is resting for a while...", + "{first} living his real life, go and live yours.", + "{first} is quite busy now-a-days.", + "I am looking for {first} too...tell me if you see him/her around", + "{first} ran away from the chat...", + "{first} is busy in his/her work ||simping||", + "{first} is busy saving the world", + "{first} is now tired fighting all the curses" +] + +back = [ + "{first} is finally back to life", + "{first} welcome back", + "{first} the spy is back watch what you talk about" + "{first} is now finally back from the dead" +] + +@Gojo.on_message(command(["afk","brb"]) & ~filters.private) +async def going_afk(c: Gojo, m: Message): + user = m.from_user.id + chat = m.chat.id + afk = AFK() + text, data_type, content = await get_afk_type(m) + + time = str(datetime.now()).rsplit(".",1)[0] + + if len(m.command) == 1: + text = choice(res) + + elif len(m.command) > 1: + text = m.text.markdown.split(None,1)[1] + + if not data_type: + data_type = Types.TEXT + + afk.insert_afk(chat,user,str(time),text,data_type,content) + + await m.reply_text(f"{m.from_user.mention} is now AFK") + + return + +async def get_hours(hour:str): + tim = hour.strip().split(":") + txt = "" + if int(tim[0]): + txt += tim[0] + " hours " + if int(tim[1]): + txt += tim[1] + " minutes " + if int(round(float(tim[2]))): + txt += str(round(float(tim[2]))) + " seconds" + + return txt + + +@Gojo.on_message(afk_filter & filters.group, 10000) +async def afk_checker(c: Gojo, m: Message): + afk = AFK() + back_ = choice(back) + user = m.from_user.id + chat = m.chat.id + repl = m.reply_to_message + + if repl and repl.from_user: + rep_user = repl.from_user.id + else: + rep_user = False + + is_afk = afk.check_afk(chat,user) + is_rep_afk = False + if rep_user: + is_rep_afk = afk.check_afk(chat,rep_user) + + if is_rep_afk and rep_user != user: + con = afk.get_afk(chat,rep_user) + time = till_date(con["time"]) + media = con["media"] + media_type = con["media_type"] + tim_ = datetime.now() - time + tim_ = str(tim_).split(",") + tim = await get_hours(tim_[-1]) + if len(tim_) == 1: + tims = tim + elif len(tim_) == 2: + tims = tim_[0] + " " + tim + reason = f"{repl.from_user.first_name} is afk since {tims}\n" + if con['reason'] not in res: + reason += f"\nDue to: {con['reason'].format(first=repl.from_user.first_name)}" + else: + reason += f"\n{con['reason'].format(first=repl.from_user.first_name)}" + txt = reason + + if media_type == Types.TEXT: + await (await send_cmd(c,media_type))( + chat, + txt, + parse_mode=PM.MARKDOWN, + reply_to_message_id=m.id, + ) + else: + await (await send_cmd(c,media_type))( + chat, + media, + txt, + parse_mode=PM.MARKDOWN, + reply_to_message_id=repl.id + ) + + if is_afk: + txt = False + try: + txt = m.command[0] + except Exception: + pass + + if txt and txt in ["afk","brb"]: + raise ContinuePropagation + else: + con = afk.get_afk(chat,user) + time = till_date(con["time"]) + tim_ = datetime.now() - time + tim_ = str(tim_).split(",") + tim = await get_hours(tim_[-1]) + if len(tim_) == 1: + tims = tim + elif len(tim_) == 2: + tims = tim_[0] + " " + tim + txt = back_.format(first=m.from_user.mention) + f"\n\nAfk for: {tims}" + await m.reply_text(txt) + afk.delete_afk(chat,user) + raise ContinuePropagation + +__PLUGIN__ = "afk" + +_DISABLE_CMDS_ = ["afk","brb"] + +__alt_name__ = ["brb"] + +__HELP__ = """ +**AFK** +โ€ข /afk (/brb) [reason | reply to a message] + +`reply to a message` can be any media or text +""" \ No newline at end of file diff --git a/Powers/plugins/antispam.py b/Powers/plugins/antispam.py index 1ca9ab818cb9d744bdc65327438b9d256e994e03..eb278055653ecdcc3b390810aee3aaef727507e7 100644 --- a/Powers/plugins/antispam.py +++ b/Powers/plugins/antispam.py @@ -5,20 +5,18 @@ from traceback import format_exc from pyrogram.errors import MessageTooLong, PeerIdInvalid, UserIsBlocked from pyrogram.types import Message -from Powers import LOGGER, MESSAGE_DUMP, SUPPORT_GROUP, TIME_ZONE +from Powers import (DEV_USERS, LOGGER, MESSAGE_DUMP, SUDO_USERS, SUPPORT_GROUP, + WHITELIST_USERS) from Powers.bot_class import Gojo from Powers.database.antispam_db import GBan from Powers.database.users_db import Users -from Powers.supports import get_support_staff from Powers.utils.clean_file import remove_markdown_and_html from Powers.utils.custom_filters import command from Powers.utils.extract_user import extract_user from Powers.utils.parser import mention_html -from Powers.vars import Config # Initialize db = GBan() -SUPPORT_STAFF = get_support_staff() @Gojo.on_message(command(["gban", "globalban"], sudo_cmd=True)) async def gban(c: Gojo, m: Message): @@ -39,11 +37,13 @@ async def gban(c: Gojo, m: Message): else: gban_reason = m.text.split(None, 2)[2] + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text(text="This user is part of my Support!, Can't ban our own!") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text( text="You don't dare use that command on me again nigga! \n Go straight and fuck your self......" ) @@ -60,7 +60,6 @@ async def gban(c: Gojo, m: Message): f"Added {user_first_name} to GBan List. \n They will now be banned in all groups where I'm admin!" ) ) - LOGGER.info(f"{m.from_user.id} gbanned {user_id} from {m.chat.id}") date = datetime.utcnow().strftime("%H:%M - %d-%m-%Y") log_msg = f"#GBAN \n Originated from: {m.chat.id} \n Admin: {await mention_html(m.from_user.first_name, m.from_user.id)} \n Gbanned User: {await mention_html(user_first_name, user_id)} \n Gbanned User ID: {user_id} \\ nEvent Stamp: {date}" await c.send_message(MESSAGE_DUMP, log_msg) @@ -70,6 +69,10 @@ async def gban(c: Gojo, m: Message): user_id, f"You have been added to my global ban list! \n Reason: {gban_reason} \n Appeal Chat: @{SUPPORT_GROUP}", ) + try: + await c.ban_chat_member(m.chat.id, user_id) + except Exception as e: + await m.reply_text(f"Failed to ban this user\n{e}") except UserIsBlocked: LOGGER.error("Could not send PM Message, user blocked bot") except PeerIdInvalid: @@ -92,11 +95,13 @@ async def ungban(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text(text="This user is part of my Support!, Can't ban our own!") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text( text="""You can't gban me nigga! Fuck yourself.......!""" @@ -107,7 +112,6 @@ async def ungban(c: Gojo, m: Message): db.remove_gban(user_id) await m.reply_text(text=f"Removed {user_first_name} from Global Ban List.") time = ((datetime.utcnow().strftime("%H:%M - %d-%m-%Y")),) - LOGGER.info(f"{m.from_user.id} ungbanned {user_id} from {m.chat.id}") log_msg = f"""#UNGBAN Originated from: {m.chat.id} Admin: {(await mention_html(m.from_user.first_name, m.from_user.id))} @@ -137,7 +141,6 @@ async def gban_count(_, m: Message): await m.reply_text( text=f"Number of people gbanned: {(db.count_gbans())}" ) - LOGGER.info(f"{m.from_user.id} counting gbans in {m.chat.id}") return @@ -153,7 +156,8 @@ async def gban_list(_, m: Message): banfile = "Here are all the globally banned geys!\n\n" for user in banned_users: - banfile += f"[x] {Users.get_user_info(user['_id'])['name']} - {user['_id']}\n" + USER = Users.get_user_info(user['_id']) + banfile += f"[x] {USER['name'] if USER else 'Name NA'} - {user['_id']}\n" if user["reason"]: banfile += f"Reason: {user['reason']}\n" @@ -166,6 +170,20 @@ async def gban_list(_, m: Message): document=f, caption="Here are all the globally banned geys!\n\n" ) - LOGGER.info(f"{m.from_user.id} exported gbanlist in {m.chat.id}") return + +__PLUGIN__ = "global" + +__alt_name__ = ["antispam", "global"] + + +__HELP__ = """ +**Global** + +**Sudo commands:** +โ€ข /gban [reply to user | user id | username]: Add the user in the global ban watchlist. +โ€ข /ungban [reply to user | user id | username]: Remove the user from the global ban watchlist. +โ€ข /numgbans : Give number of users who are banned globally. +โ€ข /gbanlist : Give list of globally banned users. +""" \ No newline at end of file diff --git a/Powers/plugins/approve.py b/Powers/plugins/approve.py index 9e9c667e84d8ea2d966edf74caca740709646c15..f84822f4d9efaee2396660732f7bc13a01fdc5a1 100644 --- a/Powers/plugins/approve.py +++ b/Powers/plugins/approve.py @@ -51,7 +51,6 @@ async def approve_user(c: Gojo, m: Message): ) return db.add_approve(user_id, user_first_name) - LOGGER.info(f"{user_id} approved by {m.from_user.id} in {m.chat.id}") # Allow all permissions try: @@ -90,7 +89,6 @@ async def disapprove_user(c: Gojo, m: Message): except UserNotParticipant: if already_approved: # If user is approved and not in chat, unapprove them. db.remove_approve(user_id) - LOGGER.info(f"{user_id} disapproved in {m.chat.id} as UserNotParticipant") await m.reply_text("This user is not in this chat, unapproved them.") return except RPCError as ef: @@ -110,7 +108,6 @@ async def disapprove_user(c: Gojo, m: Message): return db.remove_approve(user_id) - LOGGER.info(f"{user_id} disapproved by {m.from_user.id} in {m.chat.id}") # Set permission same as of current user by fetching them from chat! await m.chat.restrict_member( @@ -147,7 +144,6 @@ async def check_approved(_, m: Message): pass msg += f"- `{user_id}`: {user_name}\n" await m.reply_text(msg) - LOGGER.info(f"{m.from_user.id} checking approved users in {m.chat.id}") return @@ -160,7 +156,6 @@ async def check_approval(c: Gojo, m: Message): except Exception: return check_approve = db.check_approve(user_id) - LOGGER.info(f"{m.from_user.id} checking approval of {user_id} in {m.chat.id}") if not user_id: await m.reply_text( @@ -218,7 +213,6 @@ async def unapproveall_callback(_, q: CallbackQuery): permissions=q.message.chat.permissions, ) await q.message.delete() - LOGGER.info(f"{user_id} disapproved all users in {q.message.chat.id}") await q.answer("Disapproved all users!", show_alert=True) return diff --git a/Powers/plugins/auto_join.py b/Powers/plugins/auto_join.py new file mode 100644 index 0000000000000000000000000000000000000000..52c6d4fc18ec7d33ba7de49e1d8f18e635888959 --- /dev/null +++ b/Powers/plugins/auto_join.py @@ -0,0 +1,185 @@ +from traceback import format_exc + +from pyrogram import filters +from pyrogram.enums import ChatMemberStatus as CMS +from pyrogram.types import CallbackQuery, ChatJoinRequest +from pyrogram.types import InlineKeyboardButton as ikb +from pyrogram.types import InlineKeyboardMarkup as ikm +from pyrogram.types import Message + +from Powers import DEV_USERS, LOGGER, SUDO_USERS, WHITELIST_USERS +from Powers.bot_class import Gojo +from Powers.database.autojoin_db import AUTOJOIN +from Powers.utils.custom_filters import admin_filter, auto_join_filter, command + + +@Gojo.on_message(command(["joinreq"]) & admin_filter) +async def accept_join_requests(c: Gojo, m: Message): + if m.chat.id == m.from_user.id: + await m.reply_text("Use it in groups") + return + + split = m.command + a_j = AUTOJOIN() + + try: + status = (await m.chat.get_member(c.me.id)).status + if status != CMS.ADMINISTRATOR: + await m.reply_text("I should be admin to accept and reject join requests") + return + except Exception as ef: + await m.reply_text(f"Some error occured, report it using `/bug`\nError: {ef}") + LOGGER.error(ef) + LOGGER.error(format_exc()) + return + if len(split) == 1: + txt = "**USAGE**\n/joinreq [on | off]" + await m.reply_text(txt) + return + else: + yes_no = split[1].lower() + if yes_no not in ["on","off"]: + txt = "**USAGE**\n/joinreq [on | off]" + await m.reply_text(txt) + return + + else: + if yes_no == "on": + is_al = a_j.load_autojoin(m.chat.id) + + if is_al: + txt = "Now I will approve all the join request of the chat\nIf you want that I will just notify admins about the join request use command\n/joinreqmode [manual | auto]" + await m.reply_text(txt) + return + else: + txt = "Auto approve join request is already on for this chat\nIf you want that I will just notify admins about the join request use command\n/joinreqmode [manual | auto]" + await m.reply_text(txt) + return + + elif yes_no == "off": + a_j.remove_autojoin(m.chat.id) + txt = "Now I will neither auto approve join request nor notify any admins about it" + await m.reply_text(txt) + return + +@Gojo.on_message(command("joinreqmode") & admin_filter) +async def join_request_mode(c: Gojo, m: Message): + if m.chat.id == m.from_user.id: + await m.reply_text("Use it in groups") + return + u_text = "**USAGE**\n/joinreqmode [auto | manual]\nauto: auto approve joins\nmanual: will notify admin about the join request" + + split = m.command + a_j = AUTOJOIN() + + if len(split) == 1: + await m.reply_text(u_text) + return + + else: + auto_manual = split[1] + if auto_manual not in ["auto","manual"]: + await m.reply_text(u_text) + return + else: + a_j.update_join_type(m.chat.id,auto_manual) + txt = "Changed join request type" + await m.reply_text(txt) + return + + +@Gojo.on_chat_join_request(auto_join_filter) +async def join_request_handler(c: Gojo, j: ChatJoinRequest): + user = j.from_user.id + userr = j.from_user + chat = j.chat.id + aj = AUTOJOIN() + join_type = aj.get_autojoin(chat) + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + + if not join_type: + return + if join_type == "auto" or user in SUPPORT_STAFF: + try: + await c.approve_chat_join_request(chat,user) + await c.send_message(chat, f"Accepted join request of the {userr.mention}") + return + except Exception as ef: + await c.send_message(chat,f"Some error occured while approving request, report it using `/bug`\nError: {ef}") + LOGGER.error(ef) + LOGGER.error(format_exc()) + return + elif join_type == "manual": + txt = "New join request is available\n**USER's INFO**\n" + txt += f"Name: {userr.full_name}" + txt += f"Mention: {userr.mention}" + txt += f"Id: {user}" + txt += f"Scam: {'True' if userr.is_scam else 'False'}" + if userr.username: + txt+= f"Username: @{userr.username}" + kb = [ + [ + ikb("Accept",f"accept_joinreq_uest_{user}"), + ikb("Decline",f"decline_joinreq_uest_{user}") + ] + ] + await c.send_message(chat,txt,reply_markup=ikm(kb)) + return + +@Gojo.on_callback_query(filters.regex("^accept_joinreq_uest_") | filters.regex("^decline_joinreq_uest_")) +async def accept_decline_request(c:Gojo, q: CallbackQuery): + user_id = q.from_user.id + chat = q.message.chat.id + try: + user_status = (await q.message.chat.get_member(user_id)).status + if user_status not in {CMS.OWNER, CMS.ADMINISTRATOR}: + await q.answer( + "You're not even an admin, don't try this explosive shit!", + show_alert=True, + ) + return + except: + await q.answer("Unknow error occured. You are not admin or owner") + return + split = q.data.split("_") + chat = q.message.chat.id + user = int(split[-1]) + data = split[0] + try: + userr = await c.get_users(user) + except: + userr = None + if data == "accept": + try: + await c.approve_chat_join_request(chat,user) + await q.answer(f"Accepted join request of the {userr.mention if userr else user}",True) + await q.edit_message_text(f"Accepted join request of the {userr.mention if userr else user}") + except Exception as ef: + await c.send_message(chat,f"Some error occured while approving request, report it using `/bug`\nError: {ef}") + LOGGER.error(ef) + LOGGER.error(format_exc()) + + elif data == "decline": + try: + await c.decline_chat_join_request(chat,user) + await q.answer(f"DECLINED: {user}") + await q.edit_message_text() + except Exception as ef: + await c.send_message(chat,f"Some error occured while approving request, report it using `/bug`\nError: {ef}") + LOGGER.error(ef) + LOGGER.error(format_exc()) + + return + +__PLUGIN__ = "auto join" + +__alt_name__ = ["join_request"] + + +__HELP__ = """ +**Auto join request** + +**Admin commands:** +โ€ข /joinreq [on | off]: To switch on auto accept join request +โ€ข /joinreqmode [auto | manual]: `auto` to accept join request automatically and `manual` to get notified when new join request is available +""" \ No newline at end of file diff --git a/Powers/plugins/bans.py b/Powers/plugins/bans.py index 775468802c5218b9c2f2af765fa853900b6aaee4..69b035b8d6ceec5ca0e9fd61b772f9d29e8a5c87 100644 --- a/Powers/plugins/bans.py +++ b/Powers/plugins/bans.py @@ -3,24 +3,22 @@ from traceback import format_exc from pyrogram import enums from pyrogram.errors import (ChatAdminRequired, PeerIdInvalid, RightForbidden, - RPCError, UserAdminInvalid) + RPCError, UserAdminInvalid, UserNotParticipant) from pyrogram.filters import regex from pyrogram.types import (CallbackQuery, ChatPrivileges, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID +from Powers import (DEV_USERS, LOGGER, MESSAGE_DUMP, OWNER_ID, SUDO_USERS, + WHITELIST_USERS) from Powers.bot_class import Gojo -from Powers.supports import get_support_staff from Powers.utils.caching import ADMIN_CACHE, admin_cache_reload from Powers.utils.custom_filters import command, restrict_filter from Powers.utils.extract_user import extract_user from Powers.utils.extras import BAN_GIFS, KICK_GIFS from Powers.utils.parser import mention_html from Powers.utils.string import extract_time -from Powers.vars import Config -SUPPORT_STAFF = get_support_staff() @Gojo.on_message(command("tban") & restrict_filter) async def tban_usr(c: Gojo, m: Message): @@ -36,17 +34,17 @@ async def tban_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to ban") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("WTF?? Why would I ban myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() r_id = m.reply_to_message.id if m.reply_to_message else m.id @@ -85,7 +83,6 @@ async def tban_usr(c: Gojo, m: Message): admin = await mention_html(m.from_user.first_name, m.from_user.id) banned = await mention_html(user_first_name, user_id) chat_title = m.chat.title - LOGGER.info(f"{m.from_user.id} tbanned {user_id} in {m.chat.id}") await m.chat.ban_member( user_id, until_date=bantime) @@ -137,6 +134,8 @@ async def tban_usr(c: Gojo, m: Message): await m.reply_text( text="Cannot act on this user, maybe I wasn't the one who changed their permissions." ) + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RightForbidden: await m.reply_text(text="I don't have enough rights to ban this user.") except RPCError as ef: @@ -158,6 +157,8 @@ async def stban_usr(c: Gojo, m: Message): await m.reply_text(text="I can't ban nothing!") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + try: user_id, _, _ = await extract_user(c, m) except Exception: @@ -166,7 +167,7 @@ async def stban_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to ban") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("What the heck? Why would I ban myself?") await m.stop_propagation() @@ -174,9 +175,7 @@ async def stban_usr(c: Gojo, m: Message): await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() if m.reply_to_message and len(m.text.split()) >= 2: @@ -210,7 +209,6 @@ async def stban_usr(c: Gojo, m: Message): await m.stop_propagation() try: - LOGGER.info(f"{m.from_user.id} stbanned {user_id} in {m.chat.id}") await m.chat.ban_member(user_id, until_date=bantime) await m.delete() if m.reply_to_message: @@ -227,6 +225,8 @@ async def stban_usr(c: Gojo, m: Message): await m.reply_text( text="Cannot act on this user, maybe I wasn't the one who changed their permissions." ) + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RightForbidden: await m.reply_text(text="I don't have enough rights to ban this user.") except RPCError as ef: @@ -258,15 +258,15 @@ async def dtban_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to ban") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I ban myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text(text="I am not going to ban one of my support staff") - LOGGER.info( - f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() if m.reply_to_message and len(m.text.split()) >= 2: @@ -303,7 +303,6 @@ async def dtban_usr(c: Gojo, m: Message): admin = await mention_html(m.from_user.first_name, m.from_user.id) banned = await mention_html(user_first_name, user_id) chat_title = m.chat.title - LOGGER.info(f"{m.from_user.id} dtbanned {user_id} in {m.chat.id}") await m.chat.ban_member(user_id, until_date=bantime) await m.reply_to_message.delete() txt = f"{admin} banned {banned} in {chat_title}!" @@ -386,17 +385,17 @@ async def kick_usr(c: Gojo, m: Message): await m.reply_text("Cannot find user to kick") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I kick myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to kick {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() try: @@ -412,7 +411,6 @@ async def kick_usr(c: Gojo, m: Message): admin = await mention_html(m.from_user.first_name, m.from_user.id) kicked = await mention_html(user_first_name, user_id) chat_title = m.chat.title - LOGGER.info(f"{m.from_user.id} kicked {user_id} in {m.chat.id}") await m.chat.ban_member(user_id) txt = f"{admin} kicked {kicked} in {chat_title}!" if reason: @@ -444,6 +442,8 @@ async def kick_usr(c: Gojo, m: Message): await m.reply_text( text="Cannot act on this user, maybe I wasn't the one who changed their permissions." ) + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RightForbidden: await m.reply_text(text="I don't have enough rights to ban this user.") except RPCError as ef: @@ -473,17 +473,17 @@ async def skick_usr(c: Gojo, m: Message): await m.reply_text("Cannot find user to kick") return - if user_id == Config.BOT_ID: - await m.reply_text("Huh, why would I kick myself?") + if user_id == c.me.id: + await m.reply_text("Nuh Hu, why would I kick myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to skick {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() try: @@ -496,7 +496,6 @@ async def skick_usr(c: Gojo, m: Message): await m.stop_propagation() try: - LOGGER.info(f"{m.from_user.id} skicked {user_id} in {m.chat.id}") await m.chat.ban_member(user_id) await m.delete() if m.reply_to_message: @@ -512,6 +511,8 @@ async def skick_usr(c: Gojo, m: Message): await m.reply_text( text="Cannot act on this user, maybe I wasn't the one who changed their permissions." ) + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RightForbidden: await m.reply_text(text="I don't have enough rights to kick this user.") except RPCError as ef: @@ -543,17 +544,17 @@ async def dkick_usr(c: Gojo, m: Message): await m.reply_text("Cannot find user to kick") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I kick myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to dkick {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.stop_propagation() try: @@ -566,7 +567,6 @@ async def dkick_usr(c: Gojo, m: Message): await m.stop_propagation() try: - LOGGER.info(f"{m.from_user.id} dkicked {user_id} in {m.chat.id}") await m.reply_to_message.delete() await m.chat.ban_member(user_id) admin = await mention_html(m.from_user.first_name, m.from_user.id) @@ -601,6 +601,8 @@ async def dkick_usr(c: Gojo, m: Message): ) except RightForbidden: await m.reply_text(text="I don't have enough rights to kick this user.") + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RPCError as ef: await m.reply_text( text=f"""Some error occured, report it using `/bug` @@ -690,17 +692,16 @@ async def sban_usr(c: Gojo, m: Message): if user_id == m.chat.id: await m.reply_text("That's an admin!") await m.stop_propagation() - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I ban myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to sban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.stop_propagation() try: @@ -713,7 +714,6 @@ async def sban_usr(c: Gojo, m: Message): await m.stop_propagation() try: - LOGGER.info(f"{m.from_user.id} sbanned {user_id} in {m.chat.id}") await m.chat.ban_member(user_id) await m.delete() if m.reply_to_message: @@ -730,6 +730,8 @@ async def sban_usr(c: Gojo, m: Message): ) except RightForbidden: await m.reply_text(text="I don't have enough rights to ban this user.") + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RPCError as ef: await m.reply_text( text=f"""Some error occured, report it using `/bug` @@ -767,17 +769,16 @@ async def dban_usr(c: Gojo, m: Message): if user_id == m.chat.id: await m.reply_text("That's an admin!") await m.stop_propagation() - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I ban myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to dban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.stop_propagation() try: @@ -794,7 +795,6 @@ async def dban_usr(c: Gojo, m: Message): reason = m.text.split(None, 1)[1] try: - LOGGER.info(f"{m.from_user.id} dbanned {user_id} in {m.chat.id}") await m.reply_to_message.delete() await m.chat.ban_member(user_id) txt = f"{m.from_user.mention} banned {m.reply_to_message.from_user.mention} in {m.chat.title}!" @@ -830,6 +830,8 @@ async def dban_usr(c: Gojo, m: Message): ) except RightForbidden: await m.reply_text(text="I don't have enough rights to ban this user.") + except UserNotParticipant: + await m.reply_text("User is not part of the group") except RPCError as ef: await m.reply_text( text=f"""Some error occured, report it using `/bug` @@ -864,17 +866,16 @@ async def ban_usr(c: Gojo, m: Message): if user_id == m.chat.id: await m.reply_text("That's an admin!") await m.stop_propagation() - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I ban myself?") await m.stop_propagation() + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.stop_propagation() try: @@ -897,7 +898,6 @@ async def ban_usr(c: Gojo, m: Message): reason = m.text.split(None, 2)[2] try: - LOGGER.info(f"{m.from_user.id} banned {user_id} in {m.chat.id}") await m.chat.ban_member(user_id) banned = await mention_html(user_first_name, user_id) txt = f"{m.from_user.mention} banned {banned} in {m.chat.title}!" @@ -938,6 +938,8 @@ async def ban_usr(c: Gojo, m: Message): await m.reply_text( "I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?", ) + except UserNotParticipant: + await m.reply_text("User is not part of the group") except UserAdminInvalid: await m.reply_text( text="Cannot act on this user, maybe I wasn't the one who changed their permissions." @@ -968,7 +970,7 @@ async def unbanbutton(c: Gojo, q: CallbackQuery): ) return - if not user.privileges.can_restrict_members and q.from_user.id != OWNER_ID: + elif user and not user.privileges.can_restrict_members and q.from_user.id != OWNER_ID: await q.answer( "You don't have enough permission to do this!\nStay in your limits!", show_alert=True, @@ -991,7 +993,6 @@ async def kickme(c: Gojo, m: Message): if len(m.text.split()) >= 2: reason = m.text.split(None, 1)[1] try: - LOGGER.info(f"{m.from_user.id} kickme used by {m.from_user.id} in {m.chat.id}") mem = await c.get_chat_member(m.chat.id,m.from_user.id) if mem.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]: try: diff --git a/Powers/plugins/birthday.py b/Powers/plugins/birthday.py index 7c15c23c111da964881d477f4d3a60b242b2d7cc..ddaccb545589fb46970b3b263bb3296db480a902 100644 --- a/Powers/plugins/birthday.py +++ b/Powers/plugins/birthday.py @@ -125,7 +125,7 @@ async def who_is_next(c: Gojo, m: Message): if m.chat.type == ChatType.PRIVATE: await m.reply_text("Use it in group") return - curr = datetime.now(TIME_ZONE).date() + curr = datetime.now().date() xx = await m.reply_text("๐Ÿ“†") users = [] if blist: @@ -147,8 +147,8 @@ async def who_is_next(c: Gojo, m: Message): for i in users: DOB = give_date(i["dob"]) dete = date(curr.year, DOB.month, DOB.day) - leff = (dete - curr).days - txt += f"`{i['user_id']}` : {leff} days left" + leff = (dete - curr).days + txt += f"`{i['user_id']}` : {leff} days left\n" txt += "\n\nYou can use /info [user id] to get info about the user" await xx.delete() await m.reply_text(txt) @@ -173,22 +173,24 @@ async def cant_recall_it(c: Gojo, m: Message): await m.reply_text(f"Got an error\n{e}") return - curr = datetime.now(TIME_ZONE).date() + curr = datetime.now().date() u_dob = give_date(result["dob"]) formatted = str(u_dob.strftime('%d' + '%B %Y'))[2:-5] day = int(result["dob"].split('/')[0]) - suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(day if day < 20 else day % 10, 'th') + suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(day % 10, 'th') bday_on = f"{day}{suffix} {formatted}" - if u_dob.month < curr.month: + if (u_dob.day,u_dob.month) < (curr.day,curr.month): next_b = date(curr.year + 1, u_dob.month, u_dob.day) days_left = (next_b - curr).days - txt = f"{men} 's birthday is passed ๐Ÿซค\nDays left until next one {days_left}" + txt = f"{men} 's birthday is passed ๐Ÿซค\nDays left until next one {abs(days_left)}" txt += f"\nBirthday on: {bday_on}" txt += f"\n\nDate of birth: {result['dob']}" + elif (u_dob.day,u_dob.month) == (curr.day,curr.month): + txt = f"Today is {men}'s birthday." else: u_dobm = date(curr.year, u_dob.month, u_dob.day) days_left = (u_dobm - curr).days - txt = f"User's birthday is coming๐Ÿฅณ\nDays left : {days_left}" + txt = f"User's birthday is coming๐Ÿฅณ\nDays left: {abs(days_left)}" txt += f"\nBirthday on: {bday_on}" txt += f"\n\nDate of birth: {result['dob']}" txt+= "\n\n**NOTE**:\nDOB may be wrong if user haven't entered his/her birth year" @@ -216,7 +218,7 @@ async def chat_birthday_settings(c: Gojo, m: Message): await m.reply_text("Do you want to wish members for their birthday in the group?",reply_markup=kb) return -@Gojo.on_callback_query(filters.regex("^switchh_")) +@Gojo.on_callback_query(filters.regex(r"^switchh_(yes|no)$")) async def switch_on_off(c:Gojo, q: CallbackQuery): user = (await q.message.chat.get_member(q.from_user.id)).status await q.message.chat.get_member(q.from_user.id) @@ -225,11 +227,11 @@ async def switch_on_off(c:Gojo, q: CallbackQuery): return data = q.data.split("_")[1] chats = q.message.chat.id - xXx = {"chat_id":chats} + query = {"chat_id":chats} if data == "yes": - bday_cinfo.delete_one(xXx) + bday_cinfo.delete_one(query) elif data == "no": - bday_cinfo.insert_one(xXx) + bday_cinfo.insert_one(query) await q.edit_message_text(f"Done! I will {'wish' if data == 'yes' else 'not wish'}",reply_markup=IKM([[IKB("Close", "f_close")]])) return diff --git a/Powers/plugins/blacklist.py b/Powers/plugins/blacklist.py index 9203096475f20b7b926cf70a2b82c287ecaffe7f..768a5e4b13f82934905e0db739c3869e363307a8 100644 --- a/Powers/plugins/blacklist.py +++ b/Powers/plugins/blacklist.py @@ -15,8 +15,6 @@ from Powers.utils.kbhelpers import ikb async def view_blacklist(_, m: Message): db = Blacklist(m.chat.id) - LOGGER.info(f"{m.from_user.id} checking blacklists in {m.chat.id}") - chat_title = m.chat.title blacklists_chat = f"Current Blacklisted words in {chat_title}:\n\n" all_blacklisted = db.get_blacklists() @@ -58,7 +56,6 @@ async def add_blacklist(_, m: Message): ", ".join([f"{i}" for i in bl_words]) + " already added in blacklist, skipped them!" ) - LOGGER.info(f"{m.from_user.id} added new blacklists ({bl_words}) in {m.chat.id}") trigger = ", ".join(f"{i}" for i in bl_words) await m.reply_text( text=f"Added {trigger} in blacklist words!" @@ -116,7 +113,6 @@ async def rm_blacklist(_, m: Message): "Could not find " + ", ".join(f"{i}" for i in non_found_words) ) + " in blcklisted words, skipped them." - LOGGER.info(f"{m.from_user.id} removed blacklists ({bl_words}) in {m.chat.id}") bl_words = ", ".join(f"{i}" for i in bl_words) await m.reply_text( text=f"Removed {bl_words} from blacklist words!" @@ -145,13 +141,9 @@ async def set_bl_action(_, m: Message): return db.set_action(action) - LOGGER.info( - f"{m.from_user.id} set blacklist action to '{action}' in {m.chat.id}", - ) await m.reply_text(text=f"Set action for blacklist for this to {action}") elif len(m.text.split()) == 1: action = db.get_action() - LOGGER.info(f"{m.from_user.id} checking blacklist action in {m.chat.id}") await m.reply_text( text=f"""The current action for blacklists in this chat is {action} All blacklist modes delete the message containing blacklist word.""" @@ -201,7 +193,6 @@ async def rm_allbl_callback(_, q: CallbackQuery): return db.rm_all_blacklist() await q.message.delete() - LOGGER.info(f"{user_id} removed all blacklists in {q.message.chat.id}") await q.answer("Cleared all Blacklists!", show_alert=True) return diff --git a/Powers/plugins/botstaff.py b/Powers/plugins/botstaff.py deleted file mode 100644 index a19ab60dca19456e933ac0498c09140789bd47d3..0000000000000000000000000000000000000000 --- a/Powers/plugins/botstaff.py +++ /dev/null @@ -1,57 +0,0 @@ -from pyrogram.errors import RPCError -from pyrogram.types import Message - -from Powers import LOGGER, OWNER_ID, WHITELIST_USERS -from Powers.bot_class import Gojo -from Powers.supports import get_support_staff -from Powers.utils.custom_filters import command -from Powers.utils.parser import mention_html - -DEV_USERS = get_support_staff("dev") -SUDO_USERS = get_support_staff("sudo") - -@Gojo.on_message(command("botstaff", dev_cmd=True)) -async def botstaff(c: Gojo, m: Message): - try: - owner = await c.get_users(OWNER_ID) - reply = f"๐ŸŒŸ Owner: {(await mention_html(owner.first_name, OWNER_ID))} ({OWNER_ID})\n" - except RPCError: - pass - true_dev = list(set(DEV_USERS) - {OWNER_ID}) - reply += "\nDevelopers โšก๏ธ:\n" - if not true_dev: - reply += "No Dev Users\n" - else: - for each_user in true_dev: - user_id = int(each_user) - try: - user = await c.get_users(user_id) - reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" - except RPCError: - pass - true_sudo = list(set(SUDO_USERS) - set(DEV_USERS)) - reply += "\nSudo Users ๐Ÿ‰:\n" - if true_sudo == []: - reply += "No Sudo Users\n" - else: - for each_user in true_sudo: - user_id = int(each_user) - try: - user = await c.get_users(user_id) - reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" - except RPCError: - pass - reply += "\nWhitelisted Users ๐Ÿบ:\n" - if WHITELIST_USERS == []: - reply += "No additional whitelisted users\n" - else: - for each_user in WHITELIST_USERS: - user_id = int(each_user) - try: - user = await c.get_users(user_id) - reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" - except RPCError: - pass - await m.reply_text(reply) - LOGGER.info(f"{m.from_user.id} fetched botstaff in {m.chat.id}") - return diff --git a/Powers/plugins/captcha.py b/Powers/plugins/captcha.py new file mode 100644 index 0000000000000000000000000000000000000000..c288e4c497954f9085173c7d5735d47603f576f8 --- /dev/null +++ b/Powers/plugins/captcha.py @@ -0,0 +1,269 @@ +import os +from random import choice, shuffle +from traceback import format_exc +from typing import List + +import pyrogram +from pyrogram import filters +from pyrogram.enums import ChatMemberStatus as CMS +from pyrogram.enums import ParseMode as PM +from pyrogram.types import CallbackQuery, ChatPermissions +from pyrogram.types import InlineKeyboardButton as IKB +from pyrogram.types import InlineKeyboardMarkup as ikm +from pyrogram.types import Message, User + +from Powers import DEV_USERS, LOGGER, MESSAGE_DUMP, SUDO_USERS, WHITELIST_USERS +from Powers.bot_class import Gojo +from Powers.database.captcha_db import CAPTCHA, CAPTCHA_DATA +from Powers.utils.captcha_helper import (genrator, get_image_captcha, + get_qr_captcha) +from Powers.utils.custom_filters import admin_filter, captcha_filter, command +from Powers.utils.extras import BAN_GIFS + + +@Gojo.on_message(command("captcha") & admin_filter & ~filters.private) +async def start_captcha(_, m: Message): + captcha = CAPTCHA() + split = m.command + if len(split) == 1: + is_cap = captcha.is_captcha(m.chat.id) + if is_cap: + txt = "Captcha verification is currently **on** for this chat" + else: + txt = "Captcha verification is currently **off** for this chat" + await m.reply_text(txt) + return + else: + on_off = split[1].lower() + if on_off in ["on", "yes", "enable"]: + captcha.insert_captcha(m.chat.id) + await m.reply_text("Captcha verification is now **on** for this chat") + return + elif on_off in ["off", "no", "disable"]: + captcha.remove_captcha(m.chat.id) + await m.reply_text("Captcha verification is now **off** for this chat") + return + else: + await m.reply_text("**USAGE**\n/captcha [on | yes | enable | off | no | disable]") + return + + +@Gojo.on_message(command("captchamode") & admin_filter & ~filters.private) +async def set_captcha_mode(c: Gojo, m: Message): + split = m.command + captcha = CAPTCHA() + if len(split) == 1: + curr = captcha.get_captcha(m.chat.id) + if curr: + capatcha_type = curr["captcha_type"] + await m.reply_text(f"Current captcha verification methode is {capatcha_type}\nAvailable methodes:\nโ–  qr\nโ–  image") + return + else: + await m.reply_text("Captcha verification is off for the current chat") + return + else: + type_ = split[1].lower() + if type_ == "qr": + await m.reply_text("This feature is not implemented yet\nUse /captchamode image") + # captcha.update_type(m.chat.id, "qr") + # await m.reply_text("Captcha verification is now changed to qr code") + return + elif type_ == "image": + captcha.update_type(m.chat.id, "image") + await m.reply_text("Captcha verication is now changed to image") + return + else: + await m.reply_text("**USAGE**\n/captchamode [qr | image]") + return + + +@Gojo.on_callback_query(filters.regex("^captcha_")) +async def captcha_codes_check(c: Gojo, q: CallbackQuery): + split = q.data.split("_") + chat = int(split[1]) + user = int(split[2]) + code = split[3] + + if q.from_user.id != user: + await q.answer("Not for you BAKA!") + return + + c_data = CAPTCHA_DATA() + code_ = c_data.get_cap_data(chat, user) + + if code_ == code: + cap = "You guessed the captcha right...Now you can talk in the chat with no restrictions" + c_data.remove_cap_data(chat, user) + await q.answer(cap, True) + try: + await q.message.chat.unban_member(user) + except Exception as e: + await q.message.reply_text(f"Unable to unmute {q.from_user.mention} this user") + await q.message.reply_text(e) + return + await c.send_message(chat, f"{q.from_user.mention} now you are free to talk") + await q.message.delete() + return + else: + caps = q.message.caption.split(":") + tries = int(caps[1].strip()) - 1 + caps.pop(-1) + caps.append(f" {tries}") + new_cap = ":".join(caps) + await q.answer(f"Wrong\nTries left: {tries}", True) + if not tries: + txt = f"{q.from_user.mention} was not able to pass captcha verification thus banned from the group" + try: + await q.message.chat.ban_member(user) + except Exception as e: + await q.message.reply_text("Failed to ban member") + return + await q.message.delete() + keyboard = ikm( + [ + [ + IKB( + "Unban", + callback_data=f"unban_={user}", + ), + ], + ], + ) + anim = choice(BAN_GIFS) + try: + await c.send_animation( + chat_id=q.message.chat.id, + animation=str(anim), + caption=txt, + reply_markup=keyboard, + parse_mode=PM.HTML, + ) + except Exception: + + await c.send_animation( + chat_id=q.message.chat.id, + text=txt, + reply_markup=keyboard, + parse_mode=PM.HTML, + ) + await c.send_message(MESSAGE_DUMP,f"#REMOVE from BAN_GFIS\n{anim}") + c_data.remove_cap_data(chat, user) + c_data.del_message_id(q.message.chat.id, user) + return + else: + await q.edit_message_caption(new_cap, reply_markup=q.message.reply_markup) + return + + +@Gojo.on_message(filters.group & captcha_filter & filters.new_chat_members, group=3) +async def on_chat_members_updatess(c: Gojo, m: Message): + chat = m.chat.id + + users: List[User] = m.new_chat_members + for user in users: + captcha = CAPTCHA() + cap_data = CAPTCHA_DATA() + + if user.is_bot: + continue + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + + try: + status = (await m.chat.get_member(user)).status + if status in [CMS.OWNER, CMS.ADMINISTRATOR]: + continue + except: + pass + if user.id in SUPPORT_STAFF: + continue + captcha_info = captcha.get_captcha(chat) + captcha_type = captcha_info["captcha_type"] + is_already = cap_data.is_already_data(chat, user.id) + + mess = False + try: + if is_already: + mess = await c.get_messages(chat, int(is_already)) + except Exception: + cap_data.del_message_id(chat, is_already) + mess = False + is_already = False + + if is_already and mess.empty: + cap_data.del_message_id(chat, is_already) + continue + + try: + await c.restrict_chat_member(chat, user.id, ChatPermissions()) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + continue + + if not is_already: + captcha_type = "image" # I am not going to apply qr captcha in this update + if captcha_type == "qr": + pic = await get_qr_captcha(chat, user.id, c.me.username) + cap = f"Please {user.mention} scan this qr code with your phone to verify that you are human" + ms = await c.send_photo(chat, pic, caption=cap) + os.remove(pic) + cap_data.store_message_id(chat, user.id, ms.id) + continue + elif captcha_type == "image": + img, code = await get_image_captcha(chat, user.id) + cap = f"Please {user.mention} please choose the correct code from the one given bellow\nYou have three tries if you get all three wrong u will be banned from the chat.\nTries left: 3" + cap_data.load_cap_data(chat, user.id, code) + rand = [code] + while len(rand) != 5: + hehe = genrator() + if hehe == code: + continue + rand.append(hehe) + + shuffle(rand) + + ini = f"captcha_{chat}_{user.id}_" + + kb = ikm( + [ + [ + IKB(rand[0], ini+rand[0]) + ], + [ + IKB(rand[1], ini+rand[1]) + ], + [ + IKB(rand[2], ini+rand[2]) + ], + [ + IKB(rand[3], ini+rand[3]) + ], + [ + IKB(rand[4], ini+rand[4]) + ] + ] + ) + await c.send_photo(chat, img, caption=cap, reply_markup=kb) + os.remove(img) + continue + elif is_already and mess: + kb = ikm( + [ + [ + IKB("Click here to verify", url=mess.link) + ] + ] + ) + await c.send_message(f"{user.mention} your verification is already pending", reply_markup=kb) + continue + else: + await c.unban_chat_member(chat, user.id) + continue + + +__PLUGIN__ = "captcha" + +__HELP__ = """ +โ€ข /captcha [on|yes|enable|off|no|disable] : To enable or disable captcha verification +โ€ข /captchamode [qr|image] : To change captcha mode +""" diff --git a/Powers/plugins/chat_blacklist.py b/Powers/plugins/chat_blacklist.py index b6c25b90814b9602558d1ba169e6fd6dee23231b..16960625ac666988a6006a09307232e83327cd06 100644 --- a/Powers/plugins/chat_blacklist.py +++ b/Powers/plugins/chat_blacklist.py @@ -1,5 +1,6 @@ from traceback import format_exc +from pyrogram.enums import ChatType as CT from pyrogram.errors import PeerIdInvalid, RPCError from pyrogram.types import Message @@ -17,7 +18,6 @@ async def blacklist_chat(c: Gojo, m: Message): if len(m.text.split()) >= 2: chat_ids = m.text.split()[1:] replymsg = await m.reply_text(f"Adding {len(chat_ids)} chats to blacklist") - LOGGER.info(f"{m.from_user.id} blacklisted {chat_ids} groups for bot") for chat in chat_ids: try: get_chat = await c.get_chat(chat) @@ -33,6 +33,13 @@ async def blacklist_chat(c: Gojo, m: Message): await replymsg.edit_text( f"Added the following chats to Blacklist.\n{', '.join(chat_ids)}.", ) + else: + if m.chat.type == CT.PRIVATE: + await m.reply_text("Use in groups") + else: + chat_id = m.chat.id + db.add_chat(chat_id) + await m.reply_text("Added this chat to blacklist chats") return @@ -43,7 +50,6 @@ async def unblacklist_chat(c: Gojo, m: Message): if len(m.text.split()) >= 2: chat_ids = m.text.split()[1:] replymsg = await m.reply_text(f"Removing {len(chat_ids)} chats from blacklist") - LOGGER.info(f"{m.from_user.id} removed blacklisted {chat_ids} groups for bot") bl_chats = db.list_all_chats() for chat in chat_ids: try: @@ -63,6 +69,16 @@ async def unblacklist_chat(c: Gojo, m: Message): await replymsg.edit_text( f"Removed the following chats to Blacklist.\n{', '.join(chat_ids)}.", ) + else: + if m.chat.type == CT.PRIVATE: + await m.reply_text("Use in groups") + else: + chat_id = m.chat.id + bl_chats = bl_chats = db.list_all_chats() + if chat_id not in bl_chats: + await m.reply_text("This chat is not in my list of blacklisted chats") + else: + await m.reply_text("Removed this chat from blacklist chats") return @@ -71,7 +87,6 @@ async def unblacklist_chat(c: Gojo, m: Message): ) async def list_blacklist_chats(_, m: Message): bl_chats = db.list_all_chats() - LOGGER.info(f"{m.from_user.id} checking group blacklists in {m.chat.id}") if bl_chats: txt = ( ( @@ -84,3 +99,17 @@ async def list_blacklist_chats(_, m: Message): txt = "No chats are currently blacklisted!" await m.reply_text(txt) return + + +__PLUGIN__ = "Chat blacklist" + + + +__HELP__ = """ +**Chat blacklist** + +**Dev commands:** +โ€ข /blchat [space separated id or username of chats]: Add chats to black list if given or the current chat. +โ€ข /rmblchat [space separated id or username of chats]: Remove chats from black list if given or the current chat. +โ€ข /blchats: Give the list of blacklisted chats +""" \ No newline at end of file diff --git a/Powers/plugins/clean_db.py b/Powers/plugins/clean_db.py deleted file mode 100644 index e12f9e0c9011fa70866169a7cbce611f043b0144..0000000000000000000000000000000000000000 --- a/Powers/plugins/clean_db.py +++ /dev/null @@ -1,75 +0,0 @@ -import time -from asyncio import sleep -from traceback import format_exc - -from apscheduler.schedulers.asyncio import AsyncIOScheduler -from pyrogram.enums import ChatMemberStatus as CMS -from pyrogram.errors import PeerIdInvalid, UserNotParticipant - -from Powers import LOGGER, MESSAGE_DUMP, TIME_ZONE -from Powers.bot_class import Gojo -from Powers.database.approve_db import Approve -from Powers.database.blacklist_db import Blacklist -from Powers.database.chats_db import Chats -from Powers.database.disable_db import Disabling -from Powers.database.filters_db import Filters -from Powers.database.flood_db import Floods -from Powers.database.greetings_db import Greetings -from Powers.database.notes_db import Notes, NotesSettings -from Powers.database.pins_db import Pins -from Powers.database.reporting_db import Reporting -# from Powers.database.users_db import Users -from Powers.database.warns_db import Warns, WarnSettings -from Powers.utils.custom_filters import command -from Powers.vars import Config - - -async def clean_my_db(c:Gojo,is_cmd=False, id=None): - to_clean = list() - chats_list = Chats.list_chats_by_id() - to_clean.clear() - start = time.time() - for chats in chats_list: - try: - stat = await c.get_chat_member(chat_id=chats,user_id=Config.BOT_ID) - if stat.status not in [CMS.MEMBER, CMS.ADMINISTRATOR, CMS.OWNER]: - to_clean.append(chats) - except UserNotParticipant: - to_clean.append(chats) - except Exception as e: - LOGGER.error(e) - LOGGER.error(format_exc()) - if not is_cmd: - return e - else: - to_clean.append(chats) - for i in to_clean: - Approve(i).clean_approve() - Blacklist(i).clean_blacklist() - Chats.remove_chat(i) - Disabling(i).clean_disable() - Filters().rm_all_filters(i) - Floods().rm_flood(i) - Greetings(i).clean_greetings() - Notes().rm_all_notes(i) - NotesSettings().clean_notes(i) - Pins(i).clean_pins() - Reporting(i).clean_reporting() - Warns(i).clean_warn() - WarnSettings(i).clean_warns() - x = len(to_clean) - txt = f"#INFO\n\nCleaned db:\nTotal chats removed: {x}" - to_clean.clear() - nums = time.time()-start - if is_cmd: - txt += f"\nClean type: Forced\nInitiated by: {(await c.get_users(user_ids=id)).mention}" - txt += f"\nClean type: Manual\n\tTook {round(nums,2)} seconds to complete the process" - await c.send_message(chat_id=MESSAGE_DUMP,text=txt) - return txt - else: - txt += f"\nClean type: Auto\n\tTook {round(nums,2)} seconds to complete the process" - await c.send_message(chat_id=MESSAGE_DUMP,text=txt) - return txt - - - diff --git a/Powers/plugins/dev.py b/Powers/plugins/dev.py index 8a5064c464076aadc16fbabea02e428a48a97cfb..c64056b6bf6636b854bfda1bd4822060d2fee598 100644 --- a/Powers/plugins/dev.py +++ b/Powers/plugins/dev.py @@ -1,6 +1,7 @@ import subprocess as subp import sys from asyncio import create_subprocess_shell, sleep, subprocess +from importlib.metadata import PackageNotFoundError, metadata from io import BytesIO, StringIO from os import execvp from sys import executable @@ -15,15 +16,14 @@ from pyrogram.types import InlineKeyboardButton as IKB from pyrogram.types import InlineKeyboardMarkup as IKM from pyrogram.types import Message -from Powers import (BOT_TOKEN, LOG_DATETIME, LOGFILE, LOGGER, MESSAGE_DUMP, - OWNER_ID, UPTIME) +from Powers import (BOT_TOKEN, DEV_USERS, LOG_DATETIME, LOGFILE, LOGGER, + MESSAGE_DUMP, OWNER_ID, SUDO_USERS, UPTIME, + WHITELIST_USERS) from Powers.bot_class import Gojo from Powers.database import MongoDB from Powers.database.chats_db import Chats from Powers.database.support_db import SUPPORTS from Powers.database.users_db import Users -from Powers.plugins.scheduled_jobs import clean_my_db -from Powers.supports import get_support_staff from Powers.utils.clean_file import remove_markdown_and_html from Powers.utils.custom_filters import command from Powers.utils.extract_user import extract_user @@ -79,6 +79,12 @@ async def add_support(c: Gojo, m:Message): return else: support.insert_support_user(userr,to) + if to == "dev": + DEV_USERS.add(userr) + elif to == "sudo": + SUDO_USERS.add(userr) + else: + WHITELIST_USERS.add(userr) await m.reply_text(f"This user is now a {to} user") return can_do = can_change_type(curr_user,to) @@ -181,10 +187,13 @@ async def rm_support(c: Gojo, m: Message): return elif len(split) >= 2: try: - curr,_,_ = extract_user(m) + curr = int(split[1]) except Exception: - await m.reply_text("Dunno who u r talking abt") - return + try: + curr,_,_ = extract_user(m) + except Exception: + await m.reply_text("Dunno who u r talking abt") + return else: await m.reply_text("**USAGE**\n/rmsupport [reply to user | user id | username]") return @@ -192,6 +201,9 @@ async def rm_support(c: Gojo, m: Message): can_user = can_change_type(curr_user,to_user) if m.from_user.id == int(OWNER_ID) or can_user: support.delete_support_user(curr) + DEV_USERS.discard(curr) + SUDO_USERS.discard(curr) + WHITELIST_USERS.discard(curr) await m.reply_text("Done! User now no longer belongs to the support staff") else: await m.reply_text("Sorry you can't do that...") @@ -199,13 +211,58 @@ async def rm_support(c: Gojo, m: Message): @Gojo.on_message(command("ping", sudo_cmd=True)) async def ping(_, m: Message): - LOGGER.info(f"{m.from_user.id} used ping cmd in {m.chat.id}") start = time() replymsg = await m.reply_text(text="Pinging...", quote=True) delta_ping = time() - start await replymsg.edit_text(f"Pong!\n{delta_ping * 1000:.3f} ms") return +""" + +['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author', 'Author-email', 'License', 'Download-URL', 'Project-URL', 'Project-URL', 'Project-URL', 'Project-URL', 'Keywords', 'Platform', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Requires-Python', 'Description-Content-Type', 'License-File', 'License-File', 'License-File', 'Requires-Dist', 'Requires-Dist', 'Description'] + +""" + +@Gojo.on_message(command(["minfo", "moduleinfo"], dev_cmd=True)) +async def check_module_info(_, m: Message): + if len(m.command) != 2: + await m.reply_text("**USAGE**\n/minfo [module name]") + return + + module = m.command[-1] + + try: + minfo = metadata(module) + except PackageNotFoundError: + await m.reply_text(f"No module found with name {module}") + return + + name = minfo["Name"] + version = minfo["Version"] + summary = minfo["Summary"] + home_page = minfo["Home-Page"] + author = minfo["Author"] + license = minfo["License"] + download = minfo["Download-URL"] + + txt = f""" +Here are the info about the module **{name}** +โ€ข Version: {version} + +โ€ข Summary: {summary} + +โ€ข Home page: {home_page} + +โ€ข Author: {author} + +โ€ข License: {license} + +โ€ข Download: {download} +""" + await m.reply_text(txt, disable_web_page_preview=True) + return + + @Gojo.on_message(command("logs", dev_cmd=True)) async def send_log(c: Gojo, m: Message): @@ -336,6 +393,10 @@ async def evaluate_code(c: Gojo, m: Message): MESSAGE_DUMP, f"@{m.from_user.username} TREID TO FETCH ENV OF BOT \n userid = {m.from_user.id}", ) + final_output = f"**EVAL**: ```python\n{cmd}```\n\nOUTPUT:\n```powershell\n{evaluation}``` \n" + await sm.edit(final_output) + return + for j in HARMFUL: if j in evaluation.split() or j in cmd: if m.from_user.id != OWNER_ID: @@ -343,6 +404,9 @@ async def evaluate_code(c: Gojo, m: Message): await c.send_message( MESSAGE_DUMP, f"@{m.from_user.username} TREID TO FETCH ENV OF BOT \n userid = {m.from_user.id}") + final_output = f"**EVAL**: ```python\n{cmd}```\n\nOUTPUT:\n```powershell\n{evaluation}``` \n" + await sm.edit(final_output) + return for i in evaluation.split(): for j in i.split("="): if j and j[0] in HARMFUL: @@ -352,10 +416,12 @@ async def evaluate_code(c: Gojo, m: Message): MESSAGE_DUMP, f"@{m.from_user.username} TREID TO FETCH ENV OF BOT \n userid = {m.from_user.id}" ) - + final_output = f"**EVAL**: ```python\n{cmd}```\n\nOUTPUT:\n```powershell\n{evaluation}``` \n" + await sm.edit(final_output) + return try: - final_output = f"**EVAL**: ```python\n{cmd}```\n\nOUTPUT:\n```python\n{evaluation}``` \n" + final_output = f"**EVAL**: ```python\n{cmd}```\n\nOUTPUT:\n```powershell\n{evaluation}``` \n" await sm.edit(final_output) except MessageTooLong: final_output = f"EVAL: {cmd}\n\nOUTPUT:\n{evaluation} \n" @@ -486,7 +552,7 @@ async def stop_and_send_logger(c:Gojo,is_update=False): ) return -@Gojo.on_message(command(["restart", "update"], owner_cmd=True),group=-100) +@Gojo.on_message(command(["restart", "update"], owner_cmd=True)) async def restart_the_bot(c:Gojo,m:Message): try: cmds = m.command @@ -671,23 +737,6 @@ async def forward_type_broadcast(c: Gojo, m: Message): return -@Gojo.on_message(command(["cleandb","cleandatabase"],sudo_cmd=True)) -async def cleeeen(c:Gojo,m:Message): - x = await m.reply_text("Cleaning the database...") - try: - z = await clean_my_db(c,True,m.from_user.id) - try: - await x.delete() - except Exception: - pass - await m.reply_text(z) - return - except Exception as e: - await m.reply_text(e) - await x.delete() - LOGGER.error(e) - LOGGER.error(format_exc()) - return __PLUGIN__ = "devs" diff --git a/Powers/plugins/disable.py b/Powers/plugins/disable.py index 21e0804e9b9fb5e0bd5270318e5e2f77651b521b..a616edeb135133fdb8f2e0588fbe6790a48d7ed2 100644 --- a/Powers/plugins/disable.py +++ b/Powers/plugins/disable.py @@ -24,7 +24,6 @@ async def disableit(_, m: Message): db = Disabling(m.chat.id) disable_list = db.get_disabled() - LOGGER.info(f"{m.from_user.id} used disabled cmd in {m.chat.id}") if str(m.text.split(None, 1)[1]) in disable_list: return await m.reply_text("It's already disabled!") @@ -48,8 +47,6 @@ async def set_dsbl_action(_, m: Message): cur = True args = m.text.split(" ", 1) - LOGGER.info(f"{m.from_user.id} disabledel used in {m.chat.id}") - if len(args) >= 2: if args[1].lower() == "on": db.set_action("del") @@ -73,7 +70,6 @@ async def enableit(_, m: Message): if str(m.text.split(None, 1)[1]) not in disable_list: return await m.reply_text("It's not disabled!") db.remove_disabled((str(m.text.split(None, 1)[1])).lower()) - LOGGER.info(f"{m.from_user.id} enabled something in {m.chat.id}") return await m.reply_text(f"Enabled {m.text.split(None, 1)[1]}!") @@ -86,7 +82,6 @@ async def disabling(_, m: Message): ) tes = "List of commnds that can be disabled:\n" tes += "\n".join(f" โ€ข {escape(i)}" for i in disable_cmd_keys) - LOGGER.info(f"{m.from_user.id} checked disableable {m.chat.id}") return await m.reply_text(tes) @@ -99,7 +94,6 @@ async def disabled(_, m: Message): return tex = "Disabled commands:\n" tex += "\n".join(f" โ€ข {escape(i)}" for i in disable_list) - LOGGER.info(f"{m.from_user.id} checked disabled {m.chat.id}") return await m.reply_text(tex) @@ -145,6 +139,25 @@ async def enablealll(_, q: CallbackQuery): return db = Disabling(q.message.chat.id) db.rm_all_disabled() - LOGGER.info(f"{user_id} enabled all in {q.message.chat.id}") await q.message.edit_text("Enabled all!", show_alert=True) return + + +__PLUGIN__ = "disable able" + +__alt_name__ = ["disable commands", "disable"] + + +__HELP__ = """ +**Disable commands** + +**Admin commands:** +โ€ข /disable [command]: To disable the given command. +โ€ข /disabledel [on | off]: Will delete the command which is disabled. +โ€ข /enable [command]: To enable the given command. +โ€ข /disableable : Give all disableable commands. +โ€ข /disabled : Give all disabled commands. + +**Owner command:** +โ€ข /enableall : Enable all the disabled commands. +""" \ No newline at end of file diff --git a/Powers/plugins/filters.py b/Powers/plugins/filters.py index 78e23e1df9b2ec30f66a53ad059dd3ed6fe499c0..222dbc3a23db8e25fc2577b349b50f289b943bd9 100644 --- a/Powers/plugins/filters.py +++ b/Powers/plugins/filters.py @@ -25,8 +25,6 @@ db = Filters() @Gojo.on_message(command("filters") & filters.group & ~filters.bot) async def view_filters(_, m: Message): - LOGGER.info(f"{m.from_user.id} checking filters in {m.chat.id}") - filters_chat = f"Filters in {m.chat.title}:\n" all_filters = db.get_all_filters(m.chat.id) actual_filters = [j for i in all_filters for j in i.split("|")] @@ -66,9 +64,9 @@ async def add_filter(_, m: Message): extracted = await split_quotes(args[1]) keyword = extracted[0].lower() - for k in keyword.split("|"): - if k in actual_filters: - return await m.reply_text(f"Filter {k} already exists!") + # for k in keyword.split("|"): + # if k in actual_filters: + # return await m.reply_text(f"Filter {k} already exists!") if not keyword: return await m.reply_text( @@ -98,7 +96,6 @@ async def add_filter(_, m: Message): ) add = db.save_filter(m.chat.id, keyword, teks, msgtype, file_id) - LOGGER.info(f"{m.from_user.id} added new filter ({keyword}) in {m.chat.id}") if add: await m.reply_text( f"Saved filter for '{', '.join(keyword.split('|'))}' in {m.chat.title}!", @@ -110,7 +107,7 @@ async def add_filter(_, m: Message): async def stop_filter(_, m: Message): args = m.command - if len(args) < 1: + if len(args) <= 1: return await m.reply_text("What should I stop replying to?") chat_filters = db.get_all_filters(m.chat.id) @@ -122,7 +119,6 @@ async def stop_filter(_, m: Message): for keyword in act_filters: if keyword == m.text.split(None, 1)[1].lower(): db.rm_filter(m.chat.id, m.text.split(None, 1)[1].lower()) - LOGGER.info(f"{m.from_user.id} removed filter ({keyword}) in {m.chat.id}") await m.reply_text( f"Okay, I'll stop replying to that filter and it's aliases in {m.chat.title}.", ) @@ -171,7 +167,6 @@ async def rm_allfilters_callback(_, q: CallbackQuery): return db.rm_all_filters(q.message.chat.id) await q.message.edit_text(f"Cleared all filters for {q.message.chat.title}") - LOGGER.info(f"{user_id} removed all filter from {q.message.chat.id}") await q.answer("Cleared all Filters!", show_alert=True) return @@ -283,7 +278,6 @@ async def filters_watcher(c: Gojo, m: Message): if match: try: msgtype = await send_filter_reply(c, m, trigger) - LOGGER.info(f"Replied with {msgtype} to {trigger} in {m.chat.id}") except Exception as ef: await m.reply_text(f"Error: {ef}") LOGGER.error(ef) diff --git a/Powers/plugins/flood.py b/Powers/plugins/flood.py index 8459091fa23d9a3b5834a04964a4618ad75cbe44..0216ffe1da5b48863fc9fb78bb4f29b3396274d2 100644 --- a/Powers/plugins/flood.py +++ b/Powers/plugins/flood.py @@ -1,4 +1,5 @@ import time +from datetime import datetime, timedelta from random import choice from traceback import format_exc @@ -10,21 +11,46 @@ from pyrogram.types import (CallbackQuery, ChatPermissions, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, SUPPORT_GROUP +from Powers import DEV_USERS, LOGGER, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo -from Powers.database.approve_db import Approve from Powers.database.flood_db import Floods -from Powers.supports import get_support_staff -from Powers.utils.custom_filters import admin_filter, command +from Powers.utils.custom_filters import admin_filter, command, flood_filter from Powers.utils.extras import BAN_GIFS, KICK_GIFS, MUTE_GIFS -from Powers.utils.kbhelpers import ikb -from Powers.vars import Config - -SUPPORT_STAFF = get_support_staff() on_key = ["on", "start", "disable"] off_key = ["off", "end", "enable", "stop"] +async def get_what_temp(what): + temp_duration = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + "5 minutes", + f"f_temp_{what}_5min" + ), + InlineKeyboardButton( + "10 minute", + f"f_temp_{what}_10min", + ), + InlineKeyboardButton( + "30 minute", + f"f_temp_{what}_30min" + ), + InlineKeyboardButton( + "1 hour", + f"f_temp_{what}_60min" + ) + ], + [ + InlineKeyboardButton( + "ยซ Back", + "f_temp_back" + ) + ] + ] + ) + return temp_duration + close_kb =InlineKeyboardMarkup( [ [ @@ -52,6 +78,16 @@ action_kb = InlineKeyboardMarkup( callback_data="f_kick" ) ], + [ + InlineKeyboardButton( + "Temp Mute ๐Ÿ”‡", + "f_temp_mute" + ), + InlineKeyboardButton( + "Temp Ban ๐Ÿšท", + "f_temp_ban" + ) + ], [ InlineKeyboardButton( "โžก๏ธ Skip", @@ -114,7 +150,7 @@ limit_kb = InlineKeyboardMarkup( @Gojo.on_message(command(['floodaction','actionflood']) & admin_filter) async def flood_action(c: Gojo, m: Message): Flood = Floods() - bot = await c.get_chat_member(m.chat.id, Config.BOT_ID) + bot = await c.get_chat_member(m.chat.id, c.me.id) status = bot.status if not status in [CMS.OWNER, CMS.ADMINISTRATOR]: if not bot.privileges.can_restrict_members: @@ -151,7 +187,7 @@ async def flood_on_off(c: Gojo, m: Message): @Gojo.on_message(command(['setflood']) & ~filters.bot & admin_filter) async def flood_set(c: Gojo, m: Message): - bot = await c.get_chat_member(m.chat.id, Config.BOT_ID) + bot = await c.get_chat_member(m.chat.id, c.me.id) Flood = Floods() status = bot.status if not status in [CMS.OWNER, CMS.ADMINISTRATOR]: @@ -176,12 +212,17 @@ async def flood_set(c: Gojo, m: Message): c_id = m.chat.id if split[1].lower() in on_key: if is_flood: - return await m.reply_text(f"Flood is on for this chat\n**Action**:{saction}\n**Messages**:{slimit} within {swithin} sec") - Flood.save_flood(m.chat.id, 5, 5, 'mute') - await m.reply_text("Flood protection has been started for this group.") + saction = is_flood[2] + slimit = is_flood[0] + swithin = is_flood[1] + + await m.reply_text(f"Flood is on for this chat\n**Action**:{saction}\n**Messages**:{slimit} within {swithin} sec") return if split[1].lower() in off_key: x = Flood.rm_flood(c_id) + if not is_flood: + await m.reply_text("Flood protection is already off for this chat") + return if x: await m.reply_text("Flood protection has been stopped for this chat") return @@ -192,6 +233,7 @@ async def flood_set(c: Gojo, m: Message): @Gojo.on_callback_query(filters.regex("^f_")) async def callbacks(c: Gojo, q: CallbackQuery): + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) data = q.data if data == "f_close": await q.answer("Closed") @@ -229,6 +271,28 @@ async def callbacks(c: Gojo, q: CallbackQuery): f"Set the limit of message after the flood protection will be activated\n **CURRENT LIMIT** {slimit} messages", reply_markup=limit_kb ) + elif data.startswith("f_temp_"): + splited = data.split("_") + if len(splited) == 3: + to_do = splited[-1] + if to_do == "back": + kb = action_kb + await q.edit_message_text( + f"Choose a action given bellow to do when flood happens.\n **CURRENT ACTION** is {saction}", + reply_markup=action_kb + ) + return + kb = await get_what_temp(to_do) + await q.answer(f"Choose temp {to_do} time", True) + await q.edit_message_text(f"What shoud be temp {to_do} time?", reply_markup=kb) + else: + change = f"{splited[-2]}_{splited[-1]}" + Flood.save_flood(c_id, slimit, swithin, change) + await q.edit_message_text( + f"Set the limit of message after the flood protection will be activated\n **CURRENT LIMIT** {slimit} messages", + reply_markup=limit_kb + ) + return elif data in ["f_5", "f_10", "f_15", "f_f_f_skip"]: try: change = int(data.split("_")[-1]) @@ -263,8 +327,8 @@ async def callbacks(c: Gojo, q: CallbackQuery): "Flood protection setting has been updated", reply_markup=close_kb ) - return await q.answer("skip") + return if not change == swithin: Flood.save_flood(c_id, slimit, change, saction) await q.answer("Updated", show_alert=True) @@ -291,6 +355,7 @@ async def reverse_callbacks(c: Gojo, q: CallbackQuery): data = q.data.split("_") action = data[1] user_id = int(q.data.split("=")[1]) + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if not q.from_user: return q.answer("Looks like you are not an user ๐Ÿ‘€") if action == "ban": @@ -330,41 +395,17 @@ async def reverse_callbacks(c: Gojo, q: CallbackQuery): return dic = {} -@Gojo.on_message(filters.all & ~filters.bot | ~filters.private, 10) +@Gojo.on_message(flood_filter, 18) async def flood_watcher(c: Gojo, m: Message): c_id = m.chat.id - if not m.chat: - return - Flood = Floods() - try: - u_id = m.from_user.id - except AttributeError: - return # Get this error when the message received is not by an user and return + u_id = m.from_user.id is_flood = Flood.is_chat(c_id) - if not is_flood: - return # return of chat is not in anti flood protection - - app_users = Approve(m.chat.id).list_approved() - - if u_id in {i[0] for i in app_users}: - return #return if the user is approved - - if not is_flood or u_id in SUPPORT_STAFF: - return #return if the user is in support_staff - - try: - user_status = (await m.chat.get_member(m.from_user.id)).status - except Exception: - return - - if user_status in [CMS.OWNER, CMS.ADMINISTRATOR]: - return #return if the user is owner or admin - + action = is_flood[2] limit = int(is_flood[0]) within = int(is_flood[1]) @@ -398,6 +439,101 @@ async def flood_watcher(c: Gojo, m: Message): if len(dic[c_id][u_id][1]) == limit: if y-x <= within: + action = action.split("_") + if len(action) == 2: + try: + to_do = action[0] + for_tim = int(action[1].replace("min","")) + except: + for_tim = 30 + for_how_much = datetime.now() + timedelta(minutes=for_tim) + if to_do == "ban": + try: + await m.chat.ban_member(u_id, until_date=for_how_much) + keyboard = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + "Unban", + callback_data=f"un_ban_={u_id}", + ), + ], + ], + ) + txt = f"Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: Baned\nReason: Spaming\nUntril: {for_how_much}" + await m.reply_animation( + animation=str(choice(BAN_GIFS)), + caption=txt, + reply_markup=keyboard, + ) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + + except UserAdminInvalid: + await m.reply_text( + "I can't protect this chat from this user", + ) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + except RPCError as ef: + await m.reply_text( + text=f"""Some error occured, report it using `/bug` + + Error: {ef}""" + ) + LOGGER.error(ef) + LOGGER.error(format_exc()) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + else: + try: + await m.chat.restrict_member( + u_id, + ChatPermissions(), + until_date=for_how_much + ) + keyboard = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + "Unmute", + callback_data=f"un_mute_={u_id}", + ), + ], + ], + ) + txt = f"Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: Muted\nReason: Spaming\nUntil: {for_how_much}" + await m.reply_animation( + animation=str(choice(MUTE_GIFS)), + caption=txt, + reply_markup=keyboard, + ) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + except UserAdminInvalid: + await m.reply_text( + "I can't protect this chat from this user", + ) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + except RPCError as ef: + await m.reply_text( + text=f"""Some error occured, report it using `/bug` + + Error: {ef}""" + ) + LOGGER.error(ef) + LOGGER.error(format_exc()) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return + else: + action = action[0] if action == "ban": try: await m.chat.ban_member(u_id) @@ -442,13 +578,14 @@ async def flood_watcher(c: Gojo, m: Message): elif action == "kick": try: - await m.chat.ban_member(u_id) - txt = "Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: kicked\nReason: Spaming" + d = datetime.now()+timedelta(seconds=31) #will automatically unban user after 31 seconds kind of fail safe if unban members doesn't work properly + await m.chat.ban_member(u_id, until_date=d) + success = await c.unban_chat_member(m.chat.id, u_id) + txt = f"Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: {'kicked' if success else 'banned for 30 seconds'}\nReason: Spaming" await m.reply_animation( animation=str(choice(KICK_GIFS)), - caption=txt, + caption=txt ) - await m.chat.unban_member(u_id) dic[c_id][u_id][1].clear() dic[c_id][u_id][0].clear() return @@ -470,6 +607,12 @@ async def flood_watcher(c: Gojo, m: Message): dic[c_id][u_id][1].clear() dic[c_id][u_id][0].clear() return + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + dic[c_id][u_id][1].clear() + dic[c_id][u_id][0].clear() + return elif action == "mute": try: await m.chat.restrict_member( diff --git a/Powers/plugins/formatting.py b/Powers/plugins/formatting.py index f9bc65d52df84d399483fc5c751a50d20ccffd3c..2d4bcddf7003f3f8988b5ddaa7227df77c1e5eae 100644 --- a/Powers/plugins/formatting.py +++ b/Powers/plugins/formatting.py @@ -35,18 +35,10 @@ async def markdownhelp(_, m: Message): quote=True, reply_markup=(await gen_formatting_kb(m)), ) - LOGGER.info(f"{m.from_user.id} used cmd '{m.command}' in {m.chat.id}") return -@Gojo.on_callback_query(filters.regex("^formatting.")) -async def get_formatting_info(c: Gojo, q: CallbackQuery): - cmd = q.data.split(".")[1] - kb = ikb([[("Back", "back.formatting")]]) - - if cmd == "md_formatting": - - txt = """Markdown Formatting +md_txt = """Markdown Formatting You can format your message using bold, italic, underline, strike and much more. Go ahead and experiment! **Note**: It supports telegram user based formatting as well as html and markdown formattings. @@ -66,17 +58,74 @@ If you would like to send buttons on the same row, use the :same fo [button 2](buttonurl://example.com:same) [button 3](buttonurl://example.com) This will show button 1 and 2 on the same line, while 3 will be underneath.""" + +async def get_splited_formatting(msg, page=1): + msg = msg.split("\n") + l = len(msg) + new_msg = "" + total = l // 10 + first = 10 * (page - 1) + last = 10 * page + if not first: + for i in msg[first:last]: + new_msg += f"{i}\n" + kb = [ + [ + ("Next page โ–ถ๏ธ", f"next_format_{page+1}") + ] + ] + else: + first += 1 + if page == total: + for i in msg[first:]: + new_msg += f"{i}\n" + kb = [ + [ + ("โ—€๏ธ Previous page", f"next_format_{page-1}") + ] + ] + else: + for i in msg[first:last]: + new_msg += f"{i}\n" + kb = [ + [ + ("โ—€๏ธ Previous page", f"next_format_{page-1}"), + ("Next page โ–ถ๏ธ", f"next_format_{page+1}") + ] + ] + + + kb = ikb(kb, True, "back.formatting") + + return new_msg, kb + +@Gojo.on_callback_query(filters.regex(r"^next_format_.*[0-9]$")) +async def change_formatting_page(c: Gojo, q: CallbackQuery): + page = q.data.split("_")[-1] + txt, kb = await get_splited_formatting(md_txt, int(page)) + await q.edit_message_caption(txt, reply_markup=kb,parse_mode=enums.ParseMode.HTML,) + return + +@Gojo.on_callback_query(filters.regex("^formatting.")) +async def get_formatting_info(c: Gojo, q: CallbackQuery): + cmd = q.data.split(".")[1] + kb = ikb([[("Back", "back.formatting")]]) + + if cmd == "md_formatting": + try: await q.edit_message_caption( - caption=txt, + caption=md_txt, reply_markup=kb, parse_mode=enums.ParseMode.HTML, ) except MediaCaptionTooLong: - await c.send_message( - chat_id=q.message.chat.id, - text=txt, - parse_mode=enums.ParseMode.HTML,) + txt, kb = await get_splited_formatting(md_txt) + await q.edit_message_caption( + caption=txt, + reply_markup=kb, + parse_mode=enums.ParseMode.HTML, + ) elif cmd == "fillings": await q.edit_message_caption( caption="""Fillings diff --git a/Powers/plugins/fun.py b/Powers/plugins/fun.py index 42e56f580ce5a9819920fb43b7df0c47406bb7fc..303aab6294a103142e4036cf68ede233bd424d5d 100644 --- a/Powers/plugins/fun.py +++ b/Powers/plugins/fun.py @@ -5,15 +5,13 @@ from pyrogram import enums from pyrogram.errors import MessageTooLong from pyrogram.types import Message -from Powers import LOGGER +from Powers import DEV_USERS from Powers.bot_class import Gojo -from Powers.supports import get_support_staff from Powers.utils import extras from Powers.utils.custom_filters import command from Powers.utils.extras import NOWYES as NO from Powers.utils.extras import YESWNO as YES -DEV_USERS = get_support_staff("dev") @Gojo.on_message(command("shout")) async def fun_shout(_, m: Message): @@ -33,7 +31,6 @@ async def fun_shout(_, m: Message): result = "".join(result) msg = "```\n" + result + "```" await m.reply_text(msg, parse_mode=enums.ParseMode.MARKDOWN) - LOGGER.info(f"{m.from_user.id} shouted in {m.chat.id}") return except MessageTooLong as e: await m.reply_text(f"Error: {e}") @@ -43,7 +40,6 @@ async def fun_shout(_, m: Message): @Gojo.on_message(command("runs")) async def fun_run(_, m: Message): await m.reply_text(choice(extras.RUN_STRINGS)) - LOGGER.info(f"{m.from_user.id} runed in {m.chat.id}") return @@ -79,7 +75,6 @@ async def fun_slap(c: Gojo, m: Message): reply = temp.format(user1=user1, user2=user2, item=item, hits=hit, throws=throw) await reply_text(reply) - LOGGER.info(f"{m.from_user.id} slaped in {m.chat.id}") return @@ -87,7 +82,6 @@ async def fun_slap(c: Gojo, m: Message): async def fun_roll(_, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text await reply_text(choice(range(1, 7))) - LOGGER.info(f"{m.from_user.id} roll in {m.chat.id}") return @@ -95,7 +89,6 @@ async def fun_roll(_, m: Message): async def fun_toss(_, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text await reply_text(choice(extras.TOSS)) - LOGGER.info(f"{m.from_user.id} tossed in {m.chat.id}") return @@ -108,13 +101,9 @@ async def insult(c: Gojo, m: Message): user_first_name = m.reply_to_message.from_user.first_name if user_id in DEV_USERS: await m.reply_text("Sorry! I can't insult my devs....") - return LOGGER.info( - f"{m.from_user.id} tried to insult {user_first_name} in {m.chat.id}" - ) else: Insult_omp = choice(extras.INSULT_STRINGS) await m.reply_to_message.reply_text(Insult_omp) - LOGGER.info(f"{m.from_user.id} insulted {user_first_name} in {m.chat.id}") @Gojo.on_message(command("yes")) @@ -122,7 +111,6 @@ async def yesw(c: Gojo, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text rtext = YES[0] await reply_text(rtext) - LOGGER.info(f"{m.from_user.id} said YES or may be NO in {m.chat.id}") return @@ -131,7 +119,6 @@ async def now(c: Gojo, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text rtext = NO[0] await reply_text(rtext) - LOGGER.info(f"{m.from_user.id} said NO or may be YES in {m.chat.id}") return @@ -139,7 +126,6 @@ async def now(c: Gojo, m: Message): async def fun_shrug(_, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text await reply_text(r"ยฏ\_(ใƒ„)_/ยฏ") - LOGGER.info(f"{m.from_user.id} shruged in {m.chat.id}") return @@ -149,7 +135,6 @@ async def fun_bluetext(_, m: Message): await reply_text( "|| /BLUE /TEXT\n/MUST /CLICK\n/I /AM /A /STUPID /ANIMAL /THAT /IS /ATTRACTED /TO /COLORS ||", ) - LOGGER.info(f"{m.from_user.id} bluetexted in {m.chat.id}") return @@ -157,7 +142,6 @@ async def fun_bluetext(_, m: Message): async def fun_decide(_, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text await reply_text(choice(extras.DECIDE)) - LOGGER.info(f"{m.from_user.id} decided in {m.chat.id}") return @@ -165,7 +149,6 @@ async def fun_decide(_, m: Message): async def fun_table(_, m: Message): reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text await reply_text(choice(extras.REACTIONS)) - LOGGER.info(f"{m.from_user.id} reacted in {m.chat.id}") return @@ -199,7 +182,6 @@ async def weebify(_, m: Message): text=f"""Weebified String: {string}""" ) - LOGGER.info(f"{m.from_user.id} weebified '{args}' in {m.chat.id}") return diff --git a/Powers/plugins/greetings.py b/Powers/plugins/greetings.py index b9cdbd85e8f78c71158f9c750e74dc67dabc1753..20ce0878357f159aac0c451ca126e03ac6fc589f 100644 --- a/Powers/plugins/greetings.py +++ b/Powers/plugins/greetings.py @@ -1,45 +1,38 @@ from html import escape from secrets import choice from traceback import format_exc +from typing import List -from pyrogram import enums, filters -from pyrogram.enums import ChatMemberStatus as CMS -from pyrogram.errors import ChatAdminRequired, RPCError -from pyrogram.types import ChatMemberUpdated, Message +from pyrogram import emoji, enums, filters +from pyrogram.errors import ChannelPrivate, ChatAdminRequired, RPCError +from pyrogram.types import Message, User -from Powers import LOGGER +from Powers import DEV_USERS, LOGGER from Powers.bot_class import Gojo from Powers.database.antispam_db import GBan from Powers.database.greetings_db import Greetings -from Powers.supports import get_support_staff from Powers.utils.cmd_senders import send_cmd -from Powers.utils.custom_filters import admin_filter, bot_admin_filter, command +from Powers.utils.custom_filters import (admin_filter, bot_admin_filter, + captcha_filter, command) from Powers.utils.kbhelpers import ikb from Powers.utils.msg_types import Types, get_wlcm_type from Powers.utils.parser import escape_markdown, mention_html from Powers.utils.string import (build_keyboard, escape_invalid_curly_brackets, parse_button) -from Powers.vars import Config # Initialize gdb = GBan() -DEV_USERS = get_support_staff("dev") - ChatType = enums.ChatType -async def escape_mentions_using_curly_brackets_wl( - m: ChatMemberUpdated, - n: bool, +async def escape_mentions_using_curly_brackets_wl( + user: User, + m: Message, text: str, parse_words: list, ) -> str: teks = await escape_invalid_curly_brackets(text, parse_words) - if n: - user = m.new_chat_member.user if m.new_chat_member else m.from_user - else: - user = m.old_chat_member.user if m.old_chat_member else m.from_user if teks: teks = teks.format( first=escape(user.first_name), @@ -239,115 +232,101 @@ async def cleannnnn(_, m: Message): except Exception: pass - -@Gojo.on_chat_member_updated(filters.group, group=69) -async def member_has_joined(c: Gojo, member: ChatMemberUpdated): - - if ( - member.new_chat_member - and member.new_chat_member.status not in {CMS.BANNED, CMS.LEFT, CMS.RESTRICTED} - and not member.old_chat_member - ): - pass - else: - return - - user = member.new_chat_member.user if member.new_chat_member else member.from_user - - db = Greetings(member.chat.id) - banned_users = gdb.check_gban(user.id) - try: - if user.id == Config.BOT_ID: - return - if user.id in DEV_USERS: - await c.send_animation( - chat_id=member.chat.id, - animation="./extras/william.gif", - caption="๐Ÿ˜ณ My **DEV** has also joined the chat!", - ) - return - if banned_users: - await member.chat.ban_member(user.id) - await c.send_message( - member.chat.id, - f"{user.mention} was globally banned so i banned!", - ) - return - if user.is_bot: - return # ignore bots - except ChatAdminRequired: - return - status = db.get_welcome_status() - oo = db.get_welcome_text() - UwU = db.get_welcome_media() - mtype = db.get_welcome_msgtype() - parse_words = [ - "first", - "last", - "fullname", - "username", - "mention", - "id", - "chatname", - ] - hmm = await escape_mentions_using_curly_brackets_wl(member, True, oo, parse_words) - if status: - tek, button = await parse_button(hmm) - button = await build_keyboard(button) - button = ikb(button) if button else None - - if "%%%" in tek: - filter_reply = tek.split("%%%") - teks = choice(filter_reply) - else: - teks = tek - ifff = db.get_current_cleanwelcome_id() - gg = db.get_current_cleanwelcome_settings() - if ifff and gg: - try: - await c.delete_messages(member.chat.id, int(ifff)) - except RPCError: - pass - if not teks: - teks = "Hey {first}, welcome to {chatname}" +@Gojo.on_message(filters.group & filters.new_chat_members & ~captcha_filter, group=69) +async def member_has_joined(c: Gojo, m: Message): + users: List[User] = m.new_chat_members + db = Greetings(m.chat.id) + for user in users: + banned_users = gdb.check_gban(user.id) try: - if not UwU: - jj = await c.send_message( - member.chat.id, - text=teks, - reply_markup=button, - disable_web_page_preview=True, + if user.id == c.me.id: + continue + if user.id in DEV_USERS: + await c.send_animation( + chat_id=m.chat.id, + animation="./extras/william.gif", + caption=f"๐Ÿ˜ณ My **DEV** {user.mention} has also joined the chat!", ) - elif UwU: - jj = await (await send_cmd(c,mtype))( - member.chat.id, - UwU, - caption=teks, - reply_markup=button, + continue + if banned_users: + await m.chat.ban_member(user.id) + await c.send_message( + m.chat.id, + f"{user.mention} was globally banned so i banned!", ) + continue + if user.is_bot: + continue # ignore bots + except ChatAdminRequired: + continue + status = db.get_welcome_status() + oo = db.get_welcome_text() + UwU = db.get_welcome_media() + mtype = db.get_welcome_msgtype() + parse_words = [ + "first", + "last", + "fullname", + "username", + "mention", + "id", + "chatname", + ] + hmm = await escape_mentions_using_curly_brackets_wl(user, m, oo, parse_words) + if status: + tek, button = await parse_button(hmm) + button = await build_keyboard(button) + button = ikb(button) if button else None + + if "%%%" in tek: + filter_reply = tek.split("%%%") + teks = choice(filter_reply) + else: + teks = tek + + if not teks: + teks = f"A wild {user.mention} appeared in {m.chat.title}! Everyone be aware." + + ifff = db.get_current_cleanwelcome_id() + gg = db.get_current_cleanwelcome_settings() + if ifff and gg: + try: + await c.delete_messages(m.chat.id, int(ifff)) + except RPCError: + pass + if not teks: + teks = "Hey {first}, welcome to {chatname}" + try: + if not UwU: + jj = await c.send_message( + m.chat.id, + text=teks, + reply_markup=button, + disable_web_page_preview=True, + ) + elif UwU: + jj = await (await send_cmd(c,mtype))( + m.chat.id, + UwU, + caption=teks, + reply_markup=button, + ) + + if jj: + db.set_cleanwlcm_id(int(jj.id)) + except ChannelPrivate: + continue + except RPCError as e: + LOGGER.error(e) + LOGGER.error(format_exc(e)) + continue + else: + continue - if jj: - db.set_cleanwlcm_id(int(jj.id)) - except RPCError as e: - LOGGER.error(e) - LOGGER.error(format_exc(e)) - return - else: - return - - -@Gojo.on_chat_member_updated(filters.group, group=99) -async def member_has_left(c: Gojo, member: ChatMemberUpdated): - if ( - not member.new_chat_member - and member.old_chat_member.status not in {CMS.BANNED, CMS.RESTRICTED} - and member.old_chat_member - ): - pass - else: - return - db = Greetings(member.chat.id) +@Gojo.on_message(filters.group & filters.left_chat_member, group=99) +async def member_has_left(c: Gojo, m: Message): + db = Greetings(m.chat.id) status = db.get_goodbye_status() oo = db.get_goodbye_text() UwU = db.get_goodbye_media() @@ -362,9 +341,9 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): "chatname", ] - user = member.old_chat_member.user if member.old_chat_member else member.from_user + user = m.left_chat_member if m.left_chat_member else m.from_user - hmm = await escape_mentions_using_curly_brackets_wl(member, False, oo, parse_words) + hmm = await escape_mentions_using_curly_brackets_wl(user, m, oo, parse_words) if status: tek, button = await parse_button(hmm) button = await build_keyboard(button) @@ -375,17 +354,21 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): teks = choice(filter_reply) else: teks = tek + + if not teks: #Just in case + teks = f"Thanks for being part of this group {user.mention}. But I don't like your arrogance and leaving the group {emoji.EYES}" + ifff = db.get_current_cleangoodbye_id() iii = db.get_current_cleangoodbye_settings() if ifff and iii: try: - await c.delete_messages(member.chat.id, int(ifff)) + await c.delete_messages(m.chat.id, int(ifff)) except RPCError: pass if user.id in DEV_USERS: await c.send_message( - member.chat.id, - "Will miss you master :(", + m.chat.id, + f"Will miss you my master {user.mention} :(", ) return if not teks: @@ -393,14 +376,14 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): try: if not UwU: ooo = await c.send_message( - member.chat.id, + m.chat.id, text=teks, reply_markup=button, disable_web_page_preview=True, ) elif UwU: ooo = await (await send_cmd(c,mtype))( - member.chat.id, + m.chat.id, UwU, caption=teks, reply_markup=button, @@ -409,6 +392,8 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): if ooo: db.set_cleangoodbye_id(int(ooo.id)) return + except ChannelPrivate: + pass except RPCError as e: LOGGER.error(e) LOGGER.error(format_exc(e)) @@ -541,8 +526,6 @@ async def goodbye(c: Gojo, m: Message): reply_markup=button, ) return - return - __PLUGIN__ = "greetings" __alt_name__ = ["welcome", "goodbye", "cleanservice"] diff --git a/Powers/plugins/info.py b/Powers/plugins/info.py index 9ef892bb43710f19d3c9db3df3ab18b00bb881d7..c3698ef57f2653272bf61b11d1b0e5e8b567843d 100644 --- a/Powers/plugins/info.py +++ b/Powers/plugins/info.py @@ -9,13 +9,11 @@ from pyrogram.raw.functions.channels import GetFullChannel from pyrogram.raw.functions.users import GetFullUser from pyrogram.types import Message -from Powers import LOGGER, OWNER_ID +from Powers import DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo from Powers.database.antispam_db import GBan -from Powers.supports import get_support_staff from Powers.utils.custom_filters import command from Powers.utils.extract_user import extract_user -from Powers.vars import Config gban_db = GBan() @@ -83,10 +81,7 @@ async def user_info(c: Gojo, user, already=False): about = ll.full_user.about except Exception: pass - SUPPORT_STAFF = get_support_staff() - DEV_USERS = get_support_staff("dev") - SUDO_USERS = get_support_staff("sudo") - WHITELIST_USERS = get_support_staff("whitelist") + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) username = user.username first_name = user.first_name last_name = user.last_name @@ -96,17 +91,17 @@ async def user_info(c: Gojo, user, already=False): is_restricted = user.is_restricted photo_id = user.photo.big_file_id if user.photo else None is_support = True if user_id in SUPPORT_STAFF else False - if user_id == Config.BOT_ID: + if user_id == c.me.id: is_support = "A person is a great support to himself" omp = "Hmmm.......Who is that again?" - if is_support or Config.BOT_ID: + if is_support or c.me.id: if user_id in DEV_USERS: omp = "Dev" elif user_id in SUDO_USERS: omp = "Sudoer" elif user_id in WHITELIST_USERS: omp = "Whitelist" - elif user_id == Config.BOT_ID: + elif user_id == c.me.id: omp = "I am the targeted user" elif user_id == OWNER_ID: omp = "Owner of the bot" @@ -146,10 +141,15 @@ async def user_info(c: Gojo, user, already=False): ๐Ÿ”… Second Name: {last_name} ๐Ÿ” Username: {("@" + username) if username else "NA"} โœ๏ธ Bio: `{about}` -๐Ÿง‘โ€๐Ÿ’ป Support: {is_support} -๐Ÿฅท Support user type: {omp} -๐Ÿ’ฃ Gbanned: {gban} -โ˜ ๏ธ Gban reason: {reason} +๐Ÿง‘โ€๐Ÿ’ป Support: {is_support}\n""" + if is_support: + caption += f"๐Ÿฅท Support user type: {omp}\n๐Ÿ’ฃ Gbanned: {gban}\n" + else: + caption += f"๐Ÿ’ฃ Gbanned: {gban}\n" + + if gban: + caption += f"โ˜ ๏ธ Gban reason: {reason}\n" + caption += f""" ๐ŸŒ DC ID: {dc_id} โœ‹ RESTRICTED: {is_restricted} โœ… VERIFIED: {is_verified} @@ -157,7 +157,6 @@ async def user_info(c: Gojo, user, already=False): โš ๏ธ SCAM : {is_scam} ๐Ÿค– BOT: {is_bot} ๐Ÿ‘€ Last seen: {last_date} - """ return caption, photo_id @@ -242,8 +241,12 @@ async def info_func(c: Gojo, message: Message): if message.reply_to_message and message.reply_to_message.sender_chat: await message.reply_text("This is not a user, but rather a channel. Use `/chinfo` to fetch its information.") return - user, _, user_name = await extract_user(c, message) - + try: + user, _, user_name = await extract_user(c, message) + except: + await message.reply_text("Got Some errors failed to fetch user info") + LOGGER.error(e) + LOGGER.error(format_exc) if not user: await message.reply_text("Can't find user to fetch info!") @@ -281,6 +284,10 @@ async def info_func(c: Gojo, message: Message): LOGGER.error(rpc) LOGGER.error(format_exc()) except Exception as e: + if e == "User not found ! Error: 'InputPeerChannel' object has no attribute 'user_id'": + await m.reply_text("Looks like you are trying to fetch info of a chat not an user. In that case please use /chinfo") + return + await message.reply_text(text=e) LOGGER.error(e) LOGGER.error(format_exc()) diff --git a/Powers/plugins/locks.py b/Powers/plugins/locks.py index a877499cb461d168c1ce9fea9f7b7f0ee76fdc8c..dedc9aa54269a32485abf032d3c59c7f27f6d20c 100644 --- a/Powers/plugins/locks.py +++ b/Powers/plugins/locks.py @@ -1,21 +1,20 @@ from asyncio import sleep +from datetime import datetime, timedelta from traceback import format_exc from pyrogram import filters from pyrogram.enums import MessageEntityType as MET +from pyrogram.enums import MessageServiceType as MST from pyrogram.errors import ChatAdminRequired, ChatNotModified, RPCError -from pyrogram.types import ChatPermissions, Message +from pyrogram.types import CallbackQuery, ChatPermissions, Message -from Powers import LOGGER +from Powers import DEV_USERS, LOGGER, SUDO_USERS from Powers.bot_class import Gojo from Powers.database.approve_db import Approve from Powers.database.locks_db import LOCKS -from Powers.supports import get_support_staff from Powers.utils.caching import ADMIN_CACHE, admin_cache_reload from Powers.utils.custom_filters import command, restrict_filter -from Powers.vars import Config - -SUDO_LEVEL = get_support_staff("sudo_level") +from Powers.utils.kbhelpers import ikb l_t = """ **Lock Types:** @@ -35,7 +34,10 @@ l_t = """ - `forwardall` = Forwarding from channel and user - `forwardu` = Forwarding from user - `forwardc` = Forwarding from channel -- `links | url` = Lock links""" +- `links | url` = Lock links +- `bot` = Adding bot will be forbidden +""" + @Gojo.on_message(command("locktypes")) async def lock_types(_, m: Message): @@ -67,11 +69,12 @@ async def lock_perm(c: Gojo, m: Message): invite = get_perm.can_invite_users pin = get_perm.can_pin_messages stickers = animations = games = inlinebots = None + lock = LOCKS() if lock_type == "all": try: await c.set_chat_permissions(chat_id, ChatPermissions()) - LOGGER.info(f"{m.from_user.id} locked all permissions in {m.chat.id}") + lock.insert_lock_channel(m.chat.id, "all") except ChatNotModified: pass except ChatAdminRequired: @@ -80,8 +83,6 @@ async def lock_perm(c: Gojo, m: Message): await prevent_approved(m) return - lock = LOCKS() - if lock_type == "msg": msg = False perm = "messages" @@ -125,6 +126,13 @@ async def lock_perm(c: Gojo, m: Message): elif lock_type == "pin": pin = False perm = "pin" + elif lock_type == "bot": + curr = lock.insert_lock_channel(m.chat.id, "bot") + if not curr: + await m.reply_text("It is already on") + return + await m.reply_text("Restricted adding bots in the chat.") + return elif lock_type in ["links", "url"]: curr = lock.insert_lock_channel(m.chat.id, "anti_links") if not curr: @@ -133,28 +141,28 @@ async def lock_perm(c: Gojo, m: Message): await m.reply_text("Locked links in the chat") return elif lock_type == "anonchannel": - curr = lock.insert_lock_channel(m.chat.id,"anti_c_send") + curr = lock.insert_lock_channel(m.chat.id, "anti_c_send") if not curr: await m.reply_text("It is already on") return await m.reply_text("Locked Send As Chat") return elif lock_type == "forwardall": - curr = lock.insert_lock_channel(m.chat.id,"anti_fwd") + curr = lock.insert_lock_channel(m.chat.id, "anti_fwd") if not curr: await m.reply_text("It is already on") return await m.reply_text("Locked Forward from user as well as channel") return elif lock_type == "forwardu": - curr = lock.insert_lock_channel(m.chat.id,"anti_fwd_u") + curr = lock.insert_lock_channel(m.chat.id, "anti_fwd_u") if not curr: await m.reply_text("It is already on") return await m.reply_text("Locked Forward message from user") return elif lock_type == "forwardc": - curr = lock.insert_lock_channel(m.chat.id,"anti_fwd_c") + curr = lock.insert_lock_channel(m.chat.id, "anti_fwd_c") if not curr: await m.reply_text("It is already on") return @@ -174,7 +182,8 @@ Use /locktypes to get the lock types""" ChatPermissions( can_send_messages=msg, can_send_media_messages=media, - can_send_other_messages=any([stickers, animations, games, inlinebots]), + can_send_other_messages=any( + [stickers, animations, games, inlinebots]), can_add_web_page_previews=webprev, can_send_polls=polls, can_change_info=info, @@ -182,7 +191,6 @@ Use /locktypes to get the lock types""" can_pin_messages=pin, ), ) - LOGGER.info(f"{m.from_user.id} locked selected permissions in {m.chat.id}") except ChatNotModified: pass except ChatAdminRequired: @@ -205,24 +213,13 @@ async def view_locks(_, m: Message): return "โŒ" lock = LOCKS() - anti_c_send = lock.get_lock_channel("anti_c_send") - anti_forward = lock.get_lock_channel("anti_fwd") - anti_forward_u = lock.get_lock_channel("anti_fwd_u") - anti_forward_c = lock.get_lock_channel("anti_fwd_c") - anti_links = lock.get_lock_channel("anti_links") - anon = False - if m.chat.id in anti_c_send: - anon = True - anti_f = anti_f_u = anti_f_c = False - if m.chat.id in anti_forward: - anti_f = True - if m.chat.id in anti_forward_u: - anti_f_u = True - if m.chat.id in anti_forward_c: - anti_f_c = True - antil = False - if m.chat.id in anti_links: - antil = True + anon = lock.get_lock_channel(m.chat.id, "anti_c_send") + anti_f = lock.get_lock_channel(m.chat.id, "anti_fwd") + anti_f_u = lock.get_lock_channel(m.chat.id, "anti_fwd_u") + anti_f_c = lock.get_lock_channel(m.chat.id, "anti_fwd_c") + antil = lock.get_lock_channel(m.chat.id, "anti_links") + bots = lock.get_lock_channel(m.chat.id, "bot") + vmsg = await convert_to_emoji(v_perm.can_send_messages) vmedia = await convert_to_emoji(v_perm.can_send_media_messages) vother = await convert_to_emoji(v_perm.can_send_other_messages) @@ -236,6 +233,7 @@ async def view_locks(_, m: Message): vantiu = await convert_to_emoji(anti_f_u) vantic = await convert_to_emoji(anti_f_c) vantil = await convert_to_emoji(antil) + vantibot = await convert_to_emoji(bots) if v_perm is not None: try: @@ -256,11 +254,9 @@ async def view_locks(_, m: Message): Can forward: {vanti} Can forward from user: {vantiu} Can forward from channel and chats: {vantic} - Can send links: {antil} + Can send links: {vantil} + Can bot send messages: {vantibot} """ - LOGGER.info(f"{m.from_user.id} used locks cmd in {m.chat.id}") - await chkmsg.edit_text(permission_view_str) - except RPCError as e_f: await chkmsg.edit_text(text="Something went wrong!") await m.reply_text(e_f) @@ -279,6 +275,7 @@ async def unlock_perm(c: Gojo, m: Message): await m.reply_text(text="Specify a permission to unlock!") return + lock = LOCKS() if unlock_type == "all": try: await c.set_chat_permissions( @@ -294,7 +291,7 @@ async def unlock_perm(c: Gojo, m: Message): can_pin_messages=True, ), ) - LOGGER.info(f"{m.from_user.id} unlocked all permissions in {m.chat.id}") + lock.remove_lock_channel(m.chat.id, "all") except ChatNotModified: pass except ChatAdminRequired: @@ -314,8 +311,6 @@ async def unlock_perm(c: Gojo, m: Message): upin = get_uperm.can_pin_messages ustickers = uanimations = ugames = uinlinebots = None - lock = LOCKS() - if unlock_type == "msg": umsg = True uperm = "messages" @@ -359,16 +354,22 @@ async def unlock_perm(c: Gojo, m: Message): elif unlock_type == "pin": upin = True uperm = "pin" + elif unlock_type == "bot": + curr = lock.remove_lock_channel(m.chat.id, "bot") + if not curr: + m.reply_text("User already can add bots in the chat") + return + await m.reply_text("User are now allowed to add bots in the chat.") elif unlock_type == "anonchannel": - curr = lock.remove_lock_channel(m.chat.id,"anti_c_send") - + curr = lock.remove_lock_channel(m.chat.id, "anti_c_send") + if not curr: await m.reply_text("Send as chat is not allowed in this chat") return await m.reply_text("Send as chat is now enabled for this chat") return elif unlock_type in ["links", "url"]: - curr = lock.remove_lock_channel(m.chat.id,"anti_links") + curr = lock.remove_lock_channel(m.chat.id, "anti_links") if curr: await m.reply_text("Sending link is now allowed") return @@ -376,33 +377,33 @@ async def unlock_perm(c: Gojo, m: Message): await m.reply_text("Sending link is not allowed") return elif unlock_type == "forwardall": - curr = lock.remove_lock_channel(m.chat.id,"anti_fwd") - + curr = lock.remove_lock_channel(m.chat.id, "anti_fwd") + if not curr: await m.reply_text("Forwarding content is not allowed in this chat") return await m.reply_text("Forwarding content is now enabled for this chat") return - + elif unlock_type == "forwardu": - curr = lock.remove_lock_channel(m.chat.id,"anti_fwd_u") - + curr = lock.remove_lock_channel(m.chat.id, "anti_fwd_u") + if not curr: await m.reply_text("Forwarding content from users is not allowed in this chat") return - + await m.reply_text("Forwarding content from users is now enabled for this chat") return - + elif unlock_type == "forwardc": - curr = lock.remove_lock_channel(m.chat.id,"anti_fwd_c") - + curr = lock.remove_lock_channel(m.chat.id, "anti_fwd_c") + if not curr: await m.reply_text("Forwarding content from channel is not allowed in this chat") return await m.reply_text("Forwarding content from channel is now enabled for this chat") return - + else: await m.reply_text( text="""Invalid Lock Type! @@ -412,7 +413,6 @@ async def unlock_perm(c: Gojo, m: Message): return try: - LOGGER.info(f"{m.from_user.id} unlocked selected permissions in {m.chat.id}") await c.set_chat_permissions( chat_id, ChatPermissions( @@ -438,7 +438,8 @@ async def unlock_perm(c: Gojo, m: Message): await prevent_approved(m) return -async def delete_messages(c:Gojo, m: Message): + +async def delete_messages(c: Gojo, m: Message): try: await m.delete() return @@ -447,63 +448,87 @@ async def delete_messages(c:Gojo, m: Message): LOGGER.error(format_exc()) return -async def is_approved_user(c:Gojo, m: Message): + +async def is_approved_user(c: Gojo, m: Message): approved_users = Approve(m.chat.id).list_approved() ul = [user[0] for user in approved_users] try: admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]} except KeyError: admins_group = await admin_cache_reload(m, "lock") - + + SUDO_LEVEL = DEV_USERS.union(SUDO_USERS) + if m.forward_from: - if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == Config.BOT_ID: + if m.from_user and (m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == c.me.id): return True return False elif m.forward_from_chat: - x_chat = (await c.get_chat(m.forward_from_chat.id)).linked_chat - if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == Config.BOT_ID: + if m.from_user and (m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == c.me.id): return True - if not x_chat: - return False - elif x_chat and x_chat.id == m.chat.id: + elif m.automatic_forward: return True + else: + return False elif m.from_user: - if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == Config.BOT_ID: + if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == c.me.id: return True return False + else: + return False -@Gojo.on_message(filters.group & ~filters.me,18) -async def lock_del_mess(c:Gojo, m: Message): - lock = LOCKS() - all_chats = lock.get_lock_channel() - if not all_chats: + +@Gojo.on_message(filters.service & filters.group, 19) +async def servicess(c: Gojo, m: Message): + if m.service != MST.NEW_CHAT_MEMBERS: return - if m.chat.id not in all_chats: + approved = await is_approved_user(c, m) + if approved: return - if m.sender_chat and not (m.forward_from_chat or m.forward_from): - if m.sender_chat.id == m.chat.id: + for i in m.new_chat_members: + if i.is_bot: + try: + timee = datetime.now() + timedelta(minutes=5) + await m.chat.ban_member(i.id, until_date=timee) + sleep(1) + except Exception as ef: + LOGGER.error(ef) + LOGGER.error(format_exc()) + return + + +@Gojo.on_message(filters.group & ~filters.me, 3) +async def lock_del_mess(c: Gojo, m: Message): + lock = LOCKS() + chat_locks = lock.get_lock_channel(m.chat.id) + if not chat_locks: + return + + if chat_locks["anti_channel"] and m.sender_chat and not (m.forward_from_chat or m.forward_from): + if m.chat.is_admin: return - await delete_messages(c,m) + await delete_messages(c, m) + return + is_approved = await is_approved_user(c, m) + if is_approved: return - is_approved = await is_approved_user(c,m) entity = m.entities if m.text else m.caption_entities - if entity: + if entity and chat_locks["anti_links"]: for i in entity: if i.type in [MET.URL or MET.TEXT_LINK]: - if not is_approved: - await delete_messages(c,m) - return - elif m.forward_from or m.forward_from_chat: - if not is_approved: - if lock.is_particular_lock(m.chat.id,"anti_fwd"): - await delete_messages(c,m) - return - elif lock.is_particular_lock(m.chat.id,"anti_fwd_u") and not m.forward_from_chat: - await delete_messages(c,m) - return - elif lock.is_particular_lock(m.chat.id,"anti_fwd_c") and m.forward_from_chat: - await delete_messages(c,m) + await delete_messages(c, m) return + elif any(chat_locks["anti_fwd"].values()) and (m.forward_from or m.forward_from_chat): + if all(chat_locks["anti_fwd"].values()): + await delete_messages(c, m) + return + elif chat_locks["anti_fwd"]["user"] and not m.forward_from_chat: + await delete_messages(c, m) + return + elif chat_locks["anti_fwd"]["chat"] and m.forward_from_chat: + await delete_messages(c, m) + return + async def prevent_approved(m: Message): approved_users = Approve(m.chat.id).list_approved() @@ -513,7 +538,6 @@ async def prevent_approved(m: Message): await m.chat.unban_member(user_id=i) except (ChatAdminRequired, ChatNotModified, RPCError): continue - LOGGER.info(f"Approved {i} in {m.chat.id}") await sleep(0.1) return @@ -525,7 +549,7 @@ __alt_name__ = ["grouplock", "lock", "grouplocks"] __buttons__ = [ [ ("Lock Types", "LOCK_TYPES"), - ],] + ], ] __HELP__ = """ **Locks** @@ -541,3 +565,21 @@ Allows you to lock and unlock permission types in the chat. **Example:** `/lock media`: this locks all the media messages in the chat.""" + + +@Gojo.on_callback_query(filters.regex("^LOCK_TYPES")) +async def lock_types_callback(c: Gojo, q: CallbackQuery): + data = q.data + + if data == "LOCK_TYPES": + kb = ikb([[("Back", "LOCK_TYPES_back")]]) + await q.edit_message_caption( + l_t, + reply_markup=kb + ) + else: + kb = ikb([[("Lock Types", "LOCK_TYPES")]]) + await q.edit_message_caption( + __HELP__, + reply_markup=kb + ) diff --git a/Powers/plugins/muting.py b/Powers/plugins/muting.py index 1b0a459d39be2821f29a0d5bd76ddb34b273000f..ffdf6f2258bae067e0125ad4ec326679a97b1a30 100644 --- a/Powers/plugins/muting.py +++ b/Powers/plugins/muting.py @@ -9,18 +9,15 @@ from pyrogram.types import (CallbackQuery, ChatPermissions, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID +from Powers import DEV_USERS, LOGGER, MESSAGE_DUMP, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo -from Powers.supports import get_support_staff from Powers.utils.caching import ADMIN_CACHE, admin_cache_reload from Powers.utils.custom_filters import command, restrict_filter from Powers.utils.extract_user import extract_user from Powers.utils.extras import MUTE_GIFS from Powers.utils.parser import mention_html from Powers.utils.string import extract_time -from Powers.vars import Config -SUPPORT_STAFF = get_support_staff() @Gojo.on_message(command("tmute") & restrict_filter) async def tmute_usr(c: Gojo, m: Message): @@ -36,14 +33,14 @@ async def tmute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute !") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -86,7 +83,6 @@ async def tmute_usr(c: Gojo, m: Message): ChatPermissions(), mutetime, ) - LOGGER.info(f"{m.from_user.id} tmuted {user_id} in {m.chat.id}") admin = await mention_html(m.from_user.first_name, m.from_user.id) muted = await mention_html(user_first_name, user_id) txt = f"Admin {admin} muted {muted}!" @@ -148,14 +144,13 @@ async def dtmute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute !") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -196,7 +191,6 @@ async def dtmute_usr(c: Gojo, m: Message): ChatPermissions(), mutetime, ) - LOGGER.info(f"{m.from_user.id} dtmuted {user_id} in {m.chat.id}") await m.reply_to_message.delete() admin = await mention_html(m.from_user.first_name, m.from_user.id) muted = await mention_html(user_first_name, user_id) @@ -256,14 +250,12 @@ async def stmute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute !") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -305,7 +297,6 @@ async def stmute_usr(c: Gojo, m: Message): ChatPermissions(), mutetime, ) - LOGGER.info(f"{m.from_user.id} stmuted {user_id} in {m.chat.id}") await m.delete() if m.reply_to_message: await m.reply_to_message.delete() @@ -349,14 +340,13 @@ async def mute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) + await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -376,7 +366,6 @@ async def mute_usr(c: Gojo, m: Message): user_id, ChatPermissions(), ) - LOGGER.info(f"{m.from_user.id} muted {user_id} in {m.chat.id}") admin = await mention_html(m.from_user.first_name, m.from_user.id) muted = await mention_html(user_first_name, user_id) txt = f"Admin {admin} muted {muted}!" @@ -434,14 +423,13 @@ async def smute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -461,7 +449,6 @@ async def smute_usr(c: Gojo, m: Message): user_id, ChatPermissions(), ) - LOGGER.info(f"{m.from_user.id} smuted {user_id} in {m.chat.id}") await m.delete() if m.reply_to_message: await m.reply_to_message.delete() @@ -505,14 +492,13 @@ async def dmute_usr(c: Gojo, m: Message): if not user_id: await m.reply_text("Cannot find user to mute") return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I mute myself?") return + + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: - LOGGER.info( - f"{m.from_user.id} trying to mute {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) await m.reply_text( text="This user is in my support staff, cannot restrict them." ) @@ -532,7 +518,6 @@ async def dmute_usr(c: Gojo, m: Message): user_id, ChatPermissions(), ) - LOGGER.info(f"{m.from_user.id} dmuted {user_id} in {m.chat.id}") await m.reply_to_message.delete() admin = await mention_html(m.from_user.first_name, m.from_user.id) muted = await mention_html(user_first_name, user_id) @@ -587,7 +572,7 @@ async def unmute_usr(c: Gojo, m: Message): except Exception: return - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I unmute myself if you are using me?") return try: @@ -600,7 +585,6 @@ async def unmute_usr(c: Gojo, m: Message): LOGGER.exception(format_exc()) try: await m.chat.unban_member(user_id) - LOGGER.info(f"{m.from_user.id} unmuted {user_id} in {m.chat.id}") admin = await mention_html(m.from_user.first_name, m.from_user.id) unmuted = await mention_html(user_first_name, user_id) await m.reply_text(text=f"Admin {admin} unmuted {unmuted}!") @@ -626,14 +610,14 @@ async def unmutebutton(c: Gojo, q: CallbackQuery): user_id = int(splitter[1]) user = await q.message.chat.get_member(q.from_user.id) - if not user: + if not user or not user.privileges: await q.answer( "You don't have enough permission to do this!\nStay in your limits!", show_alert=True, ) return - if not user.privileges.can_restrict_members and user.id != OWNER_ID: + if not user.privileges.can_restrict_members: await q.answer( "You don't have enough permission to do this!\nStay in your limits!", show_alert=True, diff --git a/Powers/plugins/notes.py b/Powers/plugins/notes.py index ac632af3f220a023f9738e7ce8d818cffe30020b..a62cc3896a73a752adb37dd212de61f8364e0d52 100644 --- a/Powers/plugins/notes.py +++ b/Powers/plugins/notes.py @@ -4,7 +4,7 @@ from traceback import format_exc from pyrogram import enums, filters from pyrogram.enums import ChatMemberStatus as CMS from pyrogram.errors import RPCError -from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, Message +from pyrogram.types import CallbackQuery, Message from Powers import LOGGER from Powers.bot_class import Gojo @@ -16,7 +16,6 @@ from Powers.utils.msg_types import Types, get_note_type from Powers.utils.string import (build_keyboard, escape_mentions_using_curly_brackets, parse_button) -from Powers.vars import Config # Initialise db = Notes() @@ -60,7 +59,6 @@ async def save_note(_, m: Message): return db.save_note(m.chat.id, note_name, text, data_type, content) - LOGGER.info(f"{m.from_user.id} saved note ({note_name}) in {m.chat.id}") await m.reply_text( f"Saved note {note_name}!\nGet it with /get {note_name} or #{note_name}", ) @@ -84,7 +82,7 @@ async def get_note_func(c: Gojo, m: Message, note_name, priv_notes_status): [ ( "Click Me!", - f"https://t.me/{Config.BOT_USERNAME}?start=note_{m.chat.id}_{note_hash}", + f"https://t.me/{c.me.username}?start=note_{m.chat.id}_{note_hash}", "url", ), ], @@ -194,9 +192,7 @@ async def get_note_func(c: Gojo, m: Message, note_name, priv_notes_status): reply_markup=button, reply_to_message_id=reply_msg_id, ) - LOGGER.info( - f"{m.from_user.id} fetched note {note_name} (type - {getnotes}) in {m.chat.id}", - ) + except Exception as e: await m.reply_text(f"Error in notes: {e}") return @@ -245,9 +241,7 @@ async def get_raw_note(c: Gojo, m: Message, note: str): parse_mode=enums.ParseMode.DISABLED, reply_to_message_id=msg_id, ) - LOGGER.info( - f"{m.from_user.id} fetched raw note {note} (type - {getnotes}) in {m.chat.id}", - ) + return @@ -302,11 +296,9 @@ async def priv_notes(_, m: Message): option = (m.text.split())[1] if option in ("on", "yes"): db_settings.set_privatenotes(chat_id, True) - LOGGER.info(f"{m.from_user.id} enabled privatenotes in {m.chat.id}") msg = "Set private notes to On" elif option in ("off", "no"): db_settings.set_privatenotes(chat_id, False) - LOGGER.info(f"{m.from_user.id} disabled privatenotes in {m.chat.id}") msg = "Set private notes to Off" else: msg = "Enter correct option" @@ -314,7 +306,6 @@ async def priv_notes(_, m: Message): elif len(m.text.split()) == 1: curr_pref = db_settings.get_privatenotes(m.chat.id) msg = msg = f"Private Notes: {curr_pref}" - LOGGER.info(f"{m.from_user.id} fetched privatenotes preference in {m.chat.id}") await m.reply_text(msg) else: await m.replt_text("Check help on how to use this command!") @@ -323,8 +314,7 @@ async def priv_notes(_, m: Message): @Gojo.on_message(command("notes") & filters.group & ~filters.bot) -async def local_notes(_, m: Message): - LOGGER.info(f"{m.from_user.id} listed all notes in {m.chat.id}") +async def local_notes(c: Gojo, m: Message): getnotes = db.get_all_notes(m.chat.id) if not getnotes: @@ -341,7 +331,7 @@ async def local_notes(_, m: Message): [ ( "All Notes", - f"https://t.me/{Config.BOT_USERNAME}?start=notes_{m.chat.id}", + f"https://t.me/{c.me.username}?start=notes_{m.chat.id}", "url", ), ], @@ -372,7 +362,6 @@ async def clear_note(_, m: Message): note = m.text.split()[1].lower() getnote = db.rm_note(m.chat.id, note) - LOGGER.info(f"{m.from_user.id} cleared note ({note}) in {m.chat.id}") if not getnote: await m.reply_text("This note does not exist!") return @@ -415,7 +404,6 @@ async def clearallnotes_callback(_, q: CallbackQuery): ) return db.rm_all_notes(q.message.chat.id) - LOGGER.info(f"{user_id} removed all notes in {q.message.chat.id}") await q.message.edit_text("Cleared all notes!") return diff --git a/Powers/plugins/pin.py b/Powers/plugins/pin.py index dc7cee9e7fc3388249058c7e7b5d7b613a592d33..58ac70a04e734ee300717684705ad762499f807b 100644 --- a/Powers/plugins/pin.py +++ b/Powers/plugins/pin.py @@ -26,9 +26,7 @@ async def pin_message(_, m: Message): await m.reply_to_message.pin( disable_notification=disable_notification, ) - LOGGER.info( - f"{m.from_user.id} pinned msgid-{m.reply_to_message.id} in {m.chat.id}", - ) + if m.chat.username: # If chat has a username, use this format @@ -71,9 +69,7 @@ async def unpin_message(c: Gojo, m: Message): try: if m.reply_to_message: await m.reply_to_message.unpin() - LOGGER.info( - f"{m.from_user.id} unpinned msgid: {m.reply_to_message.id} in {m.chat.id}", - ) + await m.reply_text(text="Unpinned last message.") else: m_id = (await c.get_chat(m.chat.id)).pinned_message.id @@ -121,7 +117,6 @@ async def unpinall_calllback(c: Gojo, q: CallbackQuery): return try: await c.unpin_all_chat_messages(q.message.chat.id) - LOGGER.info(f"{q.from_user.id} unpinned all messages in {q.message.chat.id}") await q.message.edit_text(text="Unpinned all messages in this chat.") except ChatAdminRequired: await q.message.edit_text(text="I'm not admin or I don't have rights.") @@ -149,11 +144,9 @@ async def anti_channel_pin(_, m: Message): if len(m.text.split()) == 2: if m.command[1] in ("yes", "on", "true"): pinsdb.antichannelpin_on() - LOGGER.info(f"{m.from_user.id} enabled antichannelpin in {m.chat.id}") msg = "Turned on AntiChannelPin, now all message pinned by channel will be unpinned automtically!" elif m.command[1] in ("no", "off", "false"): pinsdb.antichannelpin_off() - LOGGER.info(f"{m.from_user.id} disabled antichannelpin in {m.chat.id}") msg = "Turned off AntiChannelPin, now all message pinned by channel will stay pinned!" else: await m.reply_text( @@ -201,11 +194,9 @@ async def clean_linked(_, m: Message): if len(m.text.split()) == 2: if m.command[1] in ("yes", "on", "true"): pinsdb.cleanlinked_on() - LOGGER.info(f"{m.from_user.id} enabled CleanLinked in {m.chat.id}") msg = "Turned on CleanLinked! Now all the messages from linked channel will be deleted!" elif m.command[1] in ("no", "off", "false"): pinsdb.cleanlinked_off() - LOGGER.info(f"{m.from_user.id} disabled CleanLinked in {m.chat.id}") msg = "Turned off CleanLinked! Messages from linked channel will not be deleted!" else: await m.reply_text( @@ -220,7 +211,6 @@ async def clean_linked(_, m: Message): @Gojo.on_message(command("permapin") & admin_filter) async def perma_pin(_, m: Message): if m.reply_to_message or len(m.text.split()) > 1: - LOGGER.info(f"{m.from_user.id} used permampin in {m.chat.id}") if m.reply_to_message: text = m.reply_to_message.text elif len(m.text.split()) > 1: diff --git a/Powers/plugins/purge.py b/Powers/plugins/purge.py index b71a2420c84d421cf74abbc4a62ec90e20745d83..bd4864b6fc04bf3294eefe80772f195c4bf07e8d 100644 --- a/Powers/plugins/purge.py +++ b/Powers/plugins/purge.py @@ -99,7 +99,6 @@ async def spurge(c: Gojo, m: Message): @Gojo.on_message( command("del") & admin_filter, - group=9, ) async def del_msg(c: Gojo, m: Message): diff --git a/Powers/plugins/report.py b/Powers/plugins/report.py index 0871fcb0426434cca9b8ae29566170d200588aa9..dacb246a95bb1c60d8097f63a41398560c866582 100644 --- a/Powers/plugins/report.py +++ b/Powers/plugins/report.py @@ -6,15 +6,13 @@ from pyrogram.enums import ChatType from pyrogram.errors import RPCError from pyrogram.types import CallbackQuery, Message -from Powers import LOGGER +from Powers import DEV_USERS, LOGGER, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo from Powers.database.reporting_db import Reporting -from Powers.supports import get_support_staff from Powers.utils.custom_filters import admin_filter, command from Powers.utils.kbhelpers import ikb from Powers.utils.parser import mention_html -SUPPORT_STAFF = get_support_staff() @Gojo.on_message( command("reports") & (filters.private | admin_filter), @@ -28,14 +26,9 @@ async def report_setting(_, m: Message): option = args[1].lower() if option in ("yes", "on", "true"): db.set_settings(True) - LOGGER.info(f"{m.from_user.id} enabled reports for them") - await m.reply_text( - "Turned on reporting! You'll be notified whenever anyone reports something in groups you are admin.", - ) elif option in ("no", "off", "false"): db.set_settings(False) - LOGGER.info(f"{m.from_user.id} disabled reports for them") await m.reply_text("Turned off reporting! You wont get any reports.") else: await m.reply_text( @@ -45,7 +38,6 @@ async def report_setting(_, m: Message): option = args[1].lower() if option in ("yes", "on", "true"): db.set_settings(True) - LOGGER.info(f"{m.from_user.id} enabled reports in {m.chat.id}") await m.reply_text( "Turned on reporting! Admins who have turned on reports will be notified when /report " "or @admin is called.", @@ -54,7 +46,6 @@ async def report_setting(_, m: Message): elif option in ("no", "off", "false"): db.set_settings(False) - LOGGER.info(f"{m.from_user.id} disabled reports in {m.chat.id}") await m.reply_text( "Turned off reporting! No admins will be notified on /report or @admin.", quote=True, @@ -85,7 +76,8 @@ async def report_watcher(c: Gojo, m: Message): if reported_user.id == me.id: await m.reply_text("Nice try.") return - + + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if reported_user.id in SUPPORT_STAFF: await m.reply_text("Uh? You reporting my support team?") return @@ -126,9 +118,7 @@ async def report_watcher(c: Gojo, m: Message): ], ) - LOGGER.info( - f"{m.from_user.id} reported msgid-{m.reply_to_message.id} to admins in {m.chat.id}", - ) + await m.reply_text( ( f"{(await mention_html(m.from_user.first_name, m.from_user.id))} " diff --git a/Powers/plugins/rules.py b/Powers/plugins/rules.py index 62e65a3f0c3d88fa72371f28b6361415e68e6932..a2a22ef94dc861e7d589a364d816d20303d0734f 100644 --- a/Powers/plugins/rules.py +++ b/Powers/plugins/rules.py @@ -1,5 +1,5 @@ from pyrogram import filters -from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, Message +from pyrogram.types import CallbackQuery, Message from Powers import LOGGER from Powers.bot_class import Gojo @@ -7,16 +7,14 @@ from Powers.database.rules_db import Rules from Powers.utils.custom_filters import admin_filter, command from Powers.utils.kbhelpers import ikb from Powers.utils.string import build_keyboard, parse_button -from Powers.vars import Config @Gojo.on_message(command("rules") & filters.group) -async def get_rules(_, m: Message): +async def get_rules(c: Gojo, m: Message): db = Rules(m.chat.id) msg_id = m.reply_to_message.id if m.reply_to_message else m.id rules = db.get_rules() - LOGGER.info(f"{m.from_user.id} fetched rules in {m.chat.id}") if m and not m.from_user: return @@ -35,7 +33,7 @@ async def get_rules(_, m: Message): [ ( "Rules", - f"https://t.me/{Config.BOT_USERNAME}?start=rules_{m.chat.id}", + f"https://t.me/{c.me.username}?start=rules_{m.chat.id}", "url", ), ], @@ -82,7 +80,6 @@ async def set_rules(_, m: Message): await m.reply_text("Rules are truncated to 3950 characters!") db.set_rules(rules) - LOGGER.info(f"{m.from_user.id} set rules in {m.chat.id}") await m.reply_text(text="Successfully set rules for this group.") return @@ -99,11 +96,9 @@ async def priv_rules(_, m: Message): option = (m.text.split())[1] if option in ("on", "yes"): db.set_privrules(True) - LOGGER.info(f"{m.from_user.id} enabled privaterules in {m.chat.id}") msg = f"Private Rules have been turned on for chat {m.chat.title}" elif option in ("off", "no"): db.set_privrules(False) - LOGGER.info(f"{m.from_user.id} disbaled privaterules in {m.chat.id}") msg = f"Private Rules have been turned off for chat {m.chat.title}" else: msg = "Option not valid, choose from on, yes, off, no" @@ -113,7 +108,6 @@ async def priv_rules(_, m: Message): msg = ( f"Current Preference for Private rules in this chat is: {curr_pref}" ) - LOGGER.info(f"{m.from_user.id} fetched privaterules preference in {m.chat.id}") await m.reply_text(msg) else: await m.reply_text(text="Please check help on how to use this this command.") @@ -147,7 +141,6 @@ async def clear_rules(_, m: Message): async def clearrules_callback(_, q: CallbackQuery): Rules(q.message.chat.id).clear_rules() await q.message.edit_text(text="Successfully cleared rules for this group!") - LOGGER.info(f"{q.from_user.id} cleared rules in {q.message.chat.id}") await q.answer("Rules for the chat have been cleared!", show_alert=True) return diff --git a/Powers/plugins/scheduled_jobs.py b/Powers/plugins/scheduled_jobs.py index 923cb7439d6ebd7da8c82d5e22f2daf94ac5cec7..9a4fad38af7ecbda0e64e5998b37e336e439d835 100644 --- a/Powers/plugins/scheduled_jobs.py +++ b/Powers/plugins/scheduled_jobs.py @@ -1,77 +1,10 @@ -import time -from asyncio import sleep -from traceback import format_exc - from apscheduler.schedulers.asyncio import AsyncIOScheduler from pyrogram import Client -from pyrogram.enums import ChatMemberStatus as CMS -from pyrogram.errors import UserNotParticipant -from Powers import BDB_URI, LOGGER, MESSAGE_DUMP, TIME_ZONE -from Powers.database.approve_db import Approve -from Powers.database.blacklist_db import Blacklist +from Powers import BDB_URI, TIME_ZONE from Powers.database.chats_db import Chats -from Powers.database.disable_db import Disabling -from Powers.database.filters_db import Filters -from Powers.database.flood_db import Floods -from Powers.database.greetings_db import Greetings -from Powers.database.notes_db import Notes, NotesSettings -from Powers.database.pins_db import Pins -from Powers.database.reporting_db import Reporting -# from Powers.database.users_db import Users -from Powers.database.warns_db import Warns, WarnSettings -from Powers.utils.custom_filters import command -from Powers.vars import Config - - -async def clean_my_db(c:Client,is_cmd=False, id=None): - to_clean = list() - chats_list = Chats.list_chats_by_id() - to_clean.clear() - start = time.time() - for chats in chats_list: - try: - stat = await c.get_chat_member(chat_id=chats,user_id=Config.BOT_ID) - if stat.status not in [CMS.MEMBER, CMS.ADMINISTRATOR, CMS.OWNER]: - to_clean.append(chats) - except UserNotParticipant: - to_clean.append(chats) - except Exception as e: - LOGGER.error(e) - LOGGER.error(format_exc()) - if not is_cmd: - return e - else: - to_clean.append(chats) - for i in to_clean: - Approve(i).clean_approve() - Blacklist(i).clean_blacklist() - Chats.remove_chat(i) - Disabling(i).clean_disable() - Filters().rm_all_filters(i) - Floods().rm_flood(i) - Greetings(i).clean_greetings() - Notes().rm_all_notes(i) - NotesSettings().clean_notes(i) - Pins(i).clean_pins() - Reporting(i).clean_reporting() - Warns(i).clean_warn() - WarnSettings(i).clean_warns() - x = len(to_clean) - txt = f"#INFO\n\nCleaned db:\nTotal chats removed: {x}" - to_clean.clear() - nums = time.time()-start - if is_cmd: - txt += f"\nClean type: Forced\nInitiated by: {(await c.get_users(user_ids=id)).mention}" - txt += f"\nClean type: Manual\n\tTook {round(nums,2)} seconds to complete the process" - await c.send_message(chat_id=MESSAGE_DUMP,text=txt) - return txt - else: - txt += f"\nClean type: Auto\n\tTook {round(nums,2)} seconds to complete the process" - await c.send_message(chat_id=MESSAGE_DUMP,text=txt) - return txt - +# from Powers.database.users_db import Users if BDB_URI: from Powers.plugins import bday_cinfo, bday_info @@ -105,14 +38,12 @@ async def send_wishish(JJK: Client): agee = "" if i["is_year"]: agee = curr.year - dob.year - if str(agee).endswith("1"): - agee = f"{agee}st" - elif str(agee).endswith("2"): - agee = f"{agee}nd" - elif str(agee).endswith("3"): - agee = f"{agee}rd" + suffix = {1: 'st', 2: 'nd', 3: 'rd'} + if int(agee/10) == 1: + suf = "th" else: - agee = f"{agee}th" + suffix.get((agee%10), "th") + agee = f"{agee}{suf}" U = await JJK.get_chat_member(chat_id=j,user_id=i["user_id"]) wish = choice(birthday_wish) if U.status in [ChatMemberStatus.MEMBER,ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER]: diff --git a/Powers/plugins/start.py b/Powers/plugins/start.py index 620fdbf1d64659d57b7b98faab6416af57d77ced..95e3ad5c6665973a649a57e25c60a0f36790f5e7 100644 --- a/Powers/plugins/start.py +++ b/Powers/plugins/start.py @@ -6,19 +6,22 @@ from pyrogram import enums, filters from pyrogram.enums import ChatMemberStatus as CMS from pyrogram.enums import ChatType from pyrogram.errors import (MediaCaptionTooLong, MessageNotModified, - QueryIdInvalid, UserIsBlocked) + QueryIdInvalid, RPCError, UserIsBlocked) from pyrogram.types import (CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import (HELP_COMMANDS, LOGGER, PYROGRAM_VERSION, PYTHON_VERSION, - UPTIME, VERSION) +from Powers import (DEV_USERS, HELP_COMMANDS, LOGGER, OWNER_ID, PREFIX_HANDLER, + PYROGRAM_VERSION, PYTHON_VERSION, SUDO_USERS, UPTIME, + VERSION, WHITELIST_USERS) from Powers.bot_class import Gojo +from Powers.database.captcha_db import CAPTCHA_DATA from Powers.utils.custom_filters import command from Powers.utils.extras import StartPic from Powers.utils.kbhelpers import ikb +from Powers.utils.parser import mention_html from Powers.utils.start_utils import (gen_cmds_kb, gen_start_kb, get_help_msg, get_private_note, get_private_rules) -from Powers.vars import Config +from Powers.utils.string import encode_decode @Gojo.on_message( @@ -32,10 +35,9 @@ Your donation might also me get me a new feature or two, which I wasn't able to All the fund would be put into my services such as database, storage and hosting! -You can donate by contacting my owner: [Captain Ezio](http://t.me/iamgojoof6eyes) +You can donate by contacting my owner: [Captain D. Ezio](http://t.me/iamgojoof6eyes) """ - LOGGER.info(f"{m.from_user.id} fetched donation text in {m.chat.id}") await m.reply_photo(photo=str(choice(StartPic)), caption=cpt) return @@ -68,24 +70,22 @@ async def start(c: Gojo, m: Message): if m.chat.type == ChatType.PRIVATE: if len(m.text.strip().split()) > 1: - help_option = (m.text.split(None, 1)[1]).lower() + arg = m.text.split(None, 1)[1] + help_option = arg.lower() if help_option.startswith("note") and ( help_option not in ("note", "notes") ): await get_private_note(c, m, help_option) return - + if help_option.startswith("rules"): - LOGGER.info(f"{m.from_user.id} fetched privaterules in {m.chat.id}") await get_private_rules(c, m, help_option) return - help_msg, help_kb = await get_help_msg(m, help_option) + help_msg, help_kb = await get_help_msg(c, m, help_option) - if not help_msg: - return - elif help_msg: + if help_msg: await m.reply_photo( photo=str(choice(StartPic)), caption=help_msg, @@ -94,8 +94,8 @@ async def start(c: Gojo, m: Message): quote=True, ) return - if len(help_option.split("_",1)) == 2: - if help_option.split("_")[1] == "help": + if len(arg.split("_", 1)) >= 2: + if arg.split("_")[1] == "help": await m.reply_photo( photo=str(choice(StartPic)), caption=help_msg, @@ -104,10 +104,44 @@ async def start(c: Gojo, m: Message): quote=True, ) return - + elif arg.split("_", 1)[0] == "qr": + decoded = encode_decode( + arg.split("_", 1)[1], "decode") + decode = decoded.split(":") + chat = decode[0] + user = decode[1] + if m.from_user.id != int(user): + await m.reply_text("Not for you Baka") + return + try: + await c.unban_chat_member(int(chat), int(user)) + msg = CAPTCHA_DATA().del_message_id(chat, user) + try: + chat_ = await c.get_chat(chat) + kb = ikb( + [ + [ + "Link to chat", + f"{chat_.invite_link}", + "url" + ] + ] + ) + except: + chat_ = False + kb = None + await m.reply_text("You can now talk in the chat", reply_markup=kb) + try: + await c.delete_messages(chat, msg) + except: + pass + return + except Exception: + return + try: cpt = f""" -Hey [{m.from_user.first_name}](http://t.me/{m.from_user.username})! I am Gojo โœจ. +Hey [{m.from_user.first_name}](http://t.me/{m.from_user.username})! I am {c.me.first_name} โœจ. I'm here to help you manage your group(s)! Hit /help to find out more about how to use me in my full potential! @@ -122,31 +156,31 @@ Join my [News Channel](https://t.me/gojo_bots_network) to get information on all except UserIsBlocked: LOGGER.warning(f"Bot blocked by {m.from_user.id}") else: - kb = InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - "Connect me to pm", - url=f"https://{Config.BOT_USERNAME}.t.me/", - ), - ], - ], - ) - - await m.reply_photo( - photo=str(choice(StartPic)), - caption="I'm alive :3", - reply_markup=kb, - quote=True, - ) + kb = InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + "Connect me to pm", + url=f"https://{c.me.username}.t.me/", + ), + ], + ], + ) + + await m.reply_photo( + photo=str(choice(StartPic)), + caption="I'm alive :3", + reply_markup=kb, + quote=True, + ) return @Gojo.on_callback_query(filters.regex("^start_back$")) -async def start_back(_, q: CallbackQuery): +async def start_back(c: Gojo, q: CallbackQuery): try: cpt = f""" -Hey [{q.from_user.first_name}](http://t.me/{q.from_user.username})! I am Gojo โœจ. +Hey [{q.from_user.first_name}](http://t.me/{q.from_user.username})! I am {c.me.first_name} โœจ. I'm here to help you manage your group(s)! Hit /help to find out more about how to use me in my full potential! @@ -163,18 +197,18 @@ Join my [News Channel](http://t.me/gojo_bots_network) to get information on all @Gojo.on_callback_query(filters.regex("^commands$")) -async def commands_menu(_, q: CallbackQuery): +async def commands_menu(c: Gojo, q: CallbackQuery): ou = await gen_cmds_kb(q.message) keyboard = ikb(ou, True) try: cpt = f""" -Hey **[{q.from_user.first_name}](http://t.me/{q.from_user.username})**! I am Gojoโœจ. +Hey **[{q.from_user.first_name}](http://t.me/{q.from_user.username})**! I am {c.me.first_name}โœจ. I'm here to help you manage your group(s)! Commands available: ร— /start: Start the bot ร— /help: Give's you this message. -You can use `$` and `!` in placec of `/` as your prefix handler +You can use {", ".join(PREFIX_HANDLER)} as your prefix handler """ await q.edit_message_caption( @@ -193,20 +227,17 @@ You can use `$` and `!` in placec of `/` as your prefix handler @Gojo.on_message(command("help")) -async def help_menu(_, m: Message): +async def help_menu(c: Gojo, m: Message): if len(m.text.split()) >= 2: - textt = m.text.replace(" ","_",).replace("_"," ",1) + textt = m.text.replace(" ", "_",).replace("_", " ", 1) help_option = (textt.split(None)[1]).lower() - help_msg, help_kb = await get_help_msg(m, help_option) + help_msg, help_kb = await get_help_msg(c, m, help_option) if not help_msg: - LOGGER.error(f"No help_msg found for help_option - {help_option}!!") + LOGGER.error( + f"No help_msg found for help_option - {help_option}!!") return - LOGGER.info( - f"{m.from_user.id} fetched help for '{help_option}' text in {m.chat.id}", - ) - if m.chat.type == ChatType.PRIVATE: if len(help_msg) >= 1026: await m.reply_text( @@ -225,14 +256,14 @@ async def help_menu(_, m: Message): photo=str(choice(StartPic)), caption=f"Press the button below to get help for {help_option}", reply_markup=InlineKeyboardMarkup( - [ [ - InlineKeyboardButton( - "Help", - url=f"t.me/{Config.BOT_USERNAME}?start={help_option}", - ), + [ + InlineKeyboardButton( + "Help", + url=f"t.me/{c.me.username}?start={help_option}", + ), + ], ], - ], ), ) else: @@ -241,21 +272,21 @@ async def help_menu(_, m: Message): ou = await gen_cmds_kb(m) keyboard = ikb(ou, True) msg = f""" -Hey **[{m.from_user.first_name}](http://t.me/{m.from_user.username})**!I am Gojoโœจ. +Hey **[{m.from_user.first_name}](http://t.me/{m.from_user.username})**!I am {c.me.first_name}โœจ. I'm here to help you manage your group(s)! Commands available: ร— /start: Start the bot ร— /help: Give's you this message.""" else: keyboard = InlineKeyboardMarkup( - [ [ - InlineKeyboardButton( - "Help", - url=f"t.me/{Config.BOT_USERNAME}?start=start_help", - ), + [ + InlineKeyboardButton( + "Help", + url=f"t.me/{c.me.username}?start=start_help", + ), + ], ], - ], ) msg = "Contact me in PM to get the list of possible commands." @@ -267,6 +298,65 @@ Commands available: return + +async def get_divided_msg(plugin_name: str, page:int=1, back_to_do = None): + msg = HELP_COMMANDS[plugin_name]["help_msg"] + msg = msg.split("\n") + l = len(msg) + new_msg = "" + total = l // 10 + first = 10 * (page - 1) + last = 10 * page + + if not first: + for i in msg[first:last]: + new_msg += f"{i}\n" + kb = [ + [ + ("Next page โ–ถ๏ธ", f"iter_page_{plugin_name}_{(back_to_do+'_') if back_to_do else ''}{page+1}") + ] + ] + else: + first += 1 + if page == total: + for i in msg[first:]: + new_msg += f"{i}\n" + kb = [ + [ + ("โ—€๏ธ Previous page", f"iter_page_{plugin_name}_{(back_to_do+'_') if back_to_do else ''}{page-1}") + ] + ] + else: + for i in msg[first:last]: + new_msg += f"{i}\n" + kb = [ + [ + ("โ—€๏ธ Previous page", f"iter_page_{plugin_name}_{(back_to_do+'_') if back_to_do else ''}{page-1}"), + ("Next page โ–ถ๏ธ", f"iter_page_{plugin_name}_{(back_to_do+'_') if back_to_do else ''}{page+1}") + ] + ] + if back_to_do: + kb = ikb(kb, True, back_to_do) + else: + kb = ikb(kb) + + return new_msg, kb + +@Gojo.on_callback_query(filters.regex(r"^iter_page_.*[0-9]$")) +async def helppp_page_iter(c: Gojo, q: CallbackQuery): + data = q.data.split("_") + plugin_ = data[2] + try: + back_to = data[-2] + except: + back_to = None + curr_page = int(data[-1]) + msg, kb = await get_divided_msg(plugin_, curr_page, back_to_do=back_to) + + await q.edit_message_caption(msg, reply_markup=kb) + return + + @Gojo.on_callback_query(filters.regex("^bot_curr_info$")) async def give_curr_info(c: Gojo, q: CallbackQuery): start = time() @@ -284,6 +374,7 @@ async def give_curr_info(c: Gojo, q: CallbackQuery): await q.answer(txt, show_alert=True) return + @Gojo.on_callback_query(filters.regex("^plugins.")) async def get_module_info(c: Gojo, q: CallbackQuery): module = q.data.split(".", 1)[1] @@ -292,12 +383,70 @@ async def get_module_info(c: Gojo, q: CallbackQuery): help_kb = HELP_COMMANDS[f"plugins.{module}"]["buttons"] try: - await q.edit_message_caption( - caption=help_msg, - parse_mode=enums.ParseMode.MARKDOWN, - reply_markup=ikb(help_kb, True, todo="commands"), - ) + await q.edit_message_caption( + caption=help_msg, + parse_mode=enums.ParseMode.MARKDOWN, + reply_markup=ikb(help_kb, True, todo="commands"), + ) except MediaCaptionTooLong: - await c.send_message(chat_id=q.message.chat.id,text=help_msg,) + caption, kb = await get_divided_msg(f"plugins.{module}", back_to_do="commands") + await q.edit_message_caption( + caption, + enums.ParseMode.MARKDOWN, + kb + ) await q.answer() return + + +@Gojo.on_callback_query(filters.regex("^give_bot_staffs$")) +async def give_bot_staffs(c: Gojo, q: CallbackQuery): + try: + owner = await c.get_users(OWNER_ID) + reply = f"๐ŸŒŸ Owner: {(await mention_html(owner.first_name, OWNER_ID))} ({OWNER_ID})\n" + except RPCError: + pass + true_dev = list(set(DEV_USERS) - {OWNER_ID}) + reply += "\nDevelopers โšก๏ธ:\n" + if not true_dev: + reply += "No Dev Users\n" + else: + for each_user in true_dev: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + true_sudo = list(set(SUDO_USERS) - set(DEV_USERS)) + reply += "\nSudo Users ๐Ÿ‰:\n" + if true_sudo == []: + reply += "No Sudo Users\n" + else: + for each_user in true_sudo: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + reply += "\nWhitelisted Users ๐Ÿบ:\n" + if WHITELIST_USERS == []: + reply += "No additional whitelisted users\n" + else: + for each_user in WHITELIST_USERS: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + + await q.edit_message_caption(reply, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("ยซ Back", "start_back")]])) + return + + +@Gojo.on_callback_query(filters.regex("^DELETEEEE$")) +async def delete_back(_, q: CallbackQuery): + await q.message.delete() + return diff --git a/Powers/plugins/stats.py b/Powers/plugins/stats.py index 4bdf112a4b59567e18590e231525c6da8b9b6ba3..da0bac422083ea8079fce19a6db2703384b3a482 100644 --- a/Powers/plugins/stats.py +++ b/Powers/plugins/stats.py @@ -18,7 +18,7 @@ from Powers.utils.custom_filters import command @Gojo.on_message(command("stats", dev_cmd=True)) -async def get_stats(_, m: Message): +async def get_stats(c: Gojo, m: Message): # initialise bldb = Blacklist gbandb = GBan() @@ -65,5 +65,8 @@ async def get_stats(_, m: Message): "Action:\n" f" Del: Applied in {(dsbl.count_action_dis_all('del'))} chats.\n" ) - await replymsg.edit_text(rply, parse_mode=enums.ParseMode.HTML) + try: + await replymsg.edit_text(rply, parse_mode=enums.ParseMode.HTML) + except: + await c.send_message(m.chat.id, rply, parse_mode=enums.ParseMode.HTML) return diff --git a/Powers/plugins/stickers.py b/Powers/plugins/stickers.py index f2fd72f582f3b80640c4f087e23214b0035c432f..f32dec66663aad70c46c6a1a5ac0d790264041fb 100644 --- a/Powers/plugins/stickers.py +++ b/Powers/plugins/stickers.py @@ -1,12 +1,13 @@ import os -from asyncio import gather from random import choice from traceback import format_exc +from pyrogram import filters from pyrogram.errors import (PeerIdInvalid, ShortnameOccupyFailed, StickerEmojiInvalid, StickerPngDimensions, StickerPngNopng, StickerTgsNotgs, StickerVideoNowebm, UserIsBlocked) +from pyrogram.types import CallbackQuery from pyrogram.types import InlineKeyboardButton as IKB from pyrogram.types import InlineKeyboardMarkup as IKM from pyrogram.types import Message @@ -15,8 +16,8 @@ from Powers import LOGGER from Powers.bot_class import Gojo from Powers.utils.custom_filters import command from Powers.utils.sticker_help import * +from Powers.utils.string import encode_decode from Powers.utils.web_helpers import get_file_size -from Powers.vars import Config @Gojo.on_message(command(["stickerinfo","stinfo"])) @@ -78,10 +79,13 @@ async def kang(c:Gojo, m: Message): sticker_emoji = str(args[1]) elif m.reply_to_message.sticker: try: - sticker_emoji = m.reply_to_message.sticker.emoji + sticker_emoji = m.reply_to_message.sticker.emoji + if not sticker_emoji: + ran = ["๐Ÿคฃ", "๐Ÿ˜‘", "๐Ÿ˜", "๐Ÿ‘", "๐Ÿ”ฅ", "๐Ÿ™ˆ", "๐Ÿ™", "๐Ÿ˜", "๐Ÿ˜˜", "๐Ÿ˜ฑ", "โ˜บ๏ธ", "๐Ÿ™ƒ", "๐Ÿ˜Œ", "๐Ÿคง", "๐Ÿ˜", "๐Ÿ˜ฌ", "๐Ÿคฉ", "๐Ÿ˜€", "๐Ÿ™‚", "๐Ÿฅน", "๐Ÿฅบ", "๐Ÿซฅ", "๐Ÿ™„", "๐Ÿซก", "๐Ÿซ ", "๐Ÿคซ", "๐Ÿ˜“", "๐Ÿฅต", "๐Ÿฅถ", "๐Ÿ˜ค", "๐Ÿ˜ก", "๐Ÿคฌ", "๐Ÿคฏ", "๐Ÿฅด", "๐Ÿคข", "๐Ÿคฎ", "๐Ÿ’€", "๐Ÿ—ฟ", "๐Ÿ’ฉ", "๐Ÿคก", "๐Ÿซถ", "๐Ÿ™Œ", "๐Ÿ‘", "โœŠ", "๐Ÿ‘Ž", "๐Ÿซฐ", "๐ŸคŒ", "๐Ÿ‘Œ", "๐Ÿ‘€", "๐Ÿ’ƒ", "๐Ÿ•บ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’‘", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’", "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", "๐Ÿ˜ช", "๐Ÿ˜ด", "๐Ÿ˜ญ", "๐Ÿฅธ", "๐Ÿค“", "๐Ÿซค", "๐Ÿ˜ฎ", "๐Ÿ˜ง", "๐Ÿ˜ฒ", "๐Ÿฅฑ", "๐Ÿ˜ˆ", "๐Ÿ‘ฟ", "๐Ÿค–", "๐Ÿ‘พ", "๐Ÿ™Œ", "๐Ÿฅด", "๐Ÿฅฐ", "๐Ÿ˜‡", "๐Ÿคฃ" ,"๐Ÿ˜‚", "๐Ÿ˜œ", "๐Ÿ˜Ž"] + sticker_emoji = choice(ran) except Exception: - ran = ["๐Ÿคฃ", "๐Ÿ˜‘", "๐Ÿ˜", "๐Ÿ‘", "๐Ÿ”ฅ", "๐Ÿ™ˆ", "๐Ÿ™", "๐Ÿ˜", "๐Ÿ˜˜", "๐Ÿ˜ฑ", "โ˜บ๏ธ", "๐Ÿ™ƒ", "๐Ÿ˜Œ", "๐Ÿคง", "๐Ÿ˜", "๐Ÿ˜ฌ", "๐Ÿคฉ", "๐Ÿ˜€", "๐Ÿ™‚", "๐Ÿฅน", "๐Ÿฅบ", "๐Ÿซฅ", "๐Ÿ™„", "๐Ÿซก", "๐Ÿซ ", "๐Ÿคซ", "๐Ÿ˜“", "๐Ÿฅต", "๐Ÿฅถ", "๐Ÿ˜ค", "๐Ÿ˜ก", "๐Ÿคฌ", "๐Ÿคฏ", "๐Ÿฅด", "๐Ÿคข", "๐Ÿคฎ", "๐Ÿ’€", "๐Ÿ—ฟ", "๐Ÿ’ฉ", "๐Ÿคก", "๐Ÿซถ", "๐Ÿ™Œ", "๐Ÿ‘", "โœŠ", "๐Ÿ‘Ž", "๐Ÿซฐ", "๐ŸคŒ", "๐Ÿ‘Œ", "๐Ÿ‘€", "๐Ÿ’ƒ", "๐Ÿ•บ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’‘", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’", "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", "๐Ÿ˜ช", "๐Ÿ˜ด", "๐Ÿ˜ญ", "๐Ÿฅธ", "๐Ÿค“", "๐Ÿซค", "๐Ÿ˜ฎ", "๐Ÿ˜ง", "๐Ÿ˜ฒ", "๐Ÿฅฑ", "๐Ÿ˜ˆ", "๐Ÿ‘ฟ", "๐Ÿค–", "๐Ÿ‘พ", "๐Ÿ™Œ", "๐Ÿฅด", "๐Ÿฅฐ", "๐Ÿ˜‡", "๐Ÿคฃ" ,"๐Ÿ˜‚", "๐Ÿ˜œ", "๐Ÿ˜Ž"] - sticker_emoji = choice(ran) + ran = ["๐Ÿคฃ", "๐Ÿ˜‘", "๐Ÿ˜", "๐Ÿ‘", "๐Ÿ”ฅ", "๐Ÿ™ˆ", "๐Ÿ™", "๐Ÿ˜", "๐Ÿ˜˜", "๐Ÿ˜ฑ", "โ˜บ๏ธ", "๐Ÿ™ƒ", "๐Ÿ˜Œ", "๐Ÿคง", "๐Ÿ˜", "๐Ÿ˜ฌ", "๐Ÿคฉ", "๐Ÿ˜€", "๐Ÿ™‚", "๐Ÿฅน", "๐Ÿฅบ", "๐Ÿซฅ", "๐Ÿ™„", "๐Ÿซก", "๐Ÿซ ", "๐Ÿคซ", "๐Ÿ˜“", "๐Ÿฅต", "๐Ÿฅถ", "๐Ÿ˜ค", "๐Ÿ˜ก", "๐Ÿคฌ", "๐Ÿคฏ", "๐Ÿฅด", "๐Ÿคข", "๐Ÿคฎ", "๐Ÿ’€", "๐Ÿ—ฟ", "๐Ÿ’ฉ", "๐Ÿคก", "๐Ÿซถ", "๐Ÿ™Œ", "๐Ÿ‘", "โœŠ", "๐Ÿ‘Ž", "๐Ÿซฐ", "๐ŸคŒ", "๐Ÿ‘Œ", "๐Ÿ‘€", "๐Ÿ’ƒ", "๐Ÿ•บ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’‘", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’", "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", "๐Ÿ˜ช", "๐Ÿ˜ด", "๐Ÿ˜ญ", "๐Ÿฅธ", "๐Ÿค“", "๐Ÿซค", "๐Ÿ˜ฎ", "๐Ÿ˜ง", "๐Ÿ˜ฒ", "๐Ÿฅฑ", "๐Ÿ˜ˆ", "๐Ÿ‘ฟ", "๐Ÿค–", "๐Ÿ‘พ", "๐Ÿ™Œ", "๐Ÿฅด", "๐Ÿฅฐ", "๐Ÿ˜‡", "๐Ÿคฃ" ,"๐Ÿ˜‚", "๐Ÿ˜œ", "๐Ÿ˜Ž"] + sticker_emoji = choice(ran) else: edit = await msg.reply_text("No emoji provided choosing a random emoji") ran = ["๐Ÿคฃ", "๐Ÿ˜‘", "๐Ÿ˜", "๐Ÿ‘", "๐Ÿ”ฅ", "๐Ÿ™ˆ", "๐Ÿ™", "๐Ÿ˜", "๐Ÿ˜˜", "๐Ÿ˜ฑ", "โ˜บ๏ธ", "๐Ÿ™ƒ", "๐Ÿ˜Œ", "๐Ÿคง", "๐Ÿ˜", "๐Ÿ˜ฌ", "๐Ÿคฉ", "๐Ÿ˜€", "๐Ÿ™‚", "๐Ÿฅน", "๐Ÿฅบ", "๐Ÿซฅ", "๐Ÿ™„", "๐Ÿซก", "๐Ÿซ ", "๐Ÿคซ", "๐Ÿ˜“", "๐Ÿฅต", "๐Ÿฅถ", "๐Ÿ˜ค", "๐Ÿ˜ก", "๐Ÿคฌ", "๐Ÿคฏ", "๐Ÿฅด", "๐Ÿคข", "๐Ÿคฎ", "๐Ÿ’€", "๐Ÿ—ฟ", "๐Ÿ’ฉ", "๐Ÿคก", "๐Ÿซถ", "๐Ÿ™Œ", "๐Ÿ‘", "โœŠ", "๐Ÿ‘Ž", "๐Ÿซฐ", "๐ŸคŒ", "๐Ÿ‘Œ", "๐Ÿ‘€", "๐Ÿ’ƒ", "๐Ÿ•บ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’‘", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’", "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", "๐Ÿ˜ช", "๐Ÿ˜ด", "๐Ÿ˜ญ", "๐Ÿฅธ", "๐Ÿค“", "๐Ÿซค", "๐Ÿ˜ฎ", "๐Ÿ˜ง", "๐Ÿ˜ฒ", "๐Ÿฅฑ", "๐Ÿ˜ˆ", "๐Ÿ‘ฟ", "๐Ÿค–", "๐Ÿ‘พ", "๐Ÿ™Œ", "๐Ÿฅด", "๐Ÿฅฐ", "๐Ÿ˜‡", "๐Ÿคฃ" ,"๐Ÿ˜‚", "๐Ÿ˜œ", "๐Ÿ˜Ž"] @@ -139,66 +143,40 @@ async def kang(c:Gojo, m: Message): # Find an available pack & add the sticker to the pack; create a new pack if needed # Would be a good idea to cache the number instead of searching it every single time... kang_lim = 120 - st_in = m.reply_to_message.sticker - st_type = "norm" - is_anim = is_vid = False - if st_in: - if st_in.is_animated: - st_type = "ani" - kang_lim = 50 - is_anim = True - elif st_in.is_video: - st_type = "vid" - kang_lim = 50 - is_vid = True - elif m.reply_to_message.document: - if m.reply_to_message.document.mime_type in ["application/x-bad-tgsticker", "application/x-tgsticker"]: - st_type = "ani" - kang_lim = 50 - is_anim = True - elif m.reply_to_message.document.mime_type == "video/webm": - st_type = "vid" - kang_lim = 50 - is_vid = True - elif m.reply_to_message.video or m.reply_to_message.animation or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0] == "video"): - st_type = "vid" - kang_lim = 50 - is_vid = True packnum = 0 limit = 0 volume = 0 packname_found = False - + try: while not packname_found: - packname = f"CE{str(m.from_user.id)}{st_type}{packnum}_by_{Config.BOT_USERNAME}" - kangpack = f"{('@'+m.from_user.username) if m.from_user.username else m.from_user.first_name[:10]} {st_type} {('vOl '+str(volume)) if volume else ''} by @{Config.BOT_USERNAME}" + packname = f"CE{m.from_user.id}{packnum}_by_{c.me.username}" + kangpack = f"{('@'+m.from_user.username) if m.from_user.username else m.from_user.first_name[:10]} {('vOl '+str(volume)) if volume else ''} by @{c.me.username}" if limit >= 50: # To prevent this loop from running forever await m.reply_text("Failed to kang\nMay be you have made more than 50 sticker packs with me try deleting some") return sticker_set = await get_sticker_set_by_name(c,packname) if not sticker_set: - sticker_set = await create_sticker_set( - client=c, - owner=m.from_user.id, - title=kangpack, - short_name=packname, - stickers=[sticker], - animated=is_anim, - video=is_vid - ) + try: + sticker_set = await create_sticker_set( + client=c, + owner=m.from_user.id, + title=kangpack, + short_name=packname, + stickers=[sticker] + ) + except StickerEmojiInvalid: + return await msg.edit("[ERROR]: INVALID_EMOJI_IN_ARGUMENT") elif sticker_set.set.count >= kang_lim: packnum += 1 limit += 1 volume += 1 continue - else: - try: - await add_sticker_to_set(c,sticker_set,sticker) - except StickerEmojiInvalid: - return await msg.edit("[ERROR]: INVALID_EMOJI_IN_ARGUMENT") - limit += 1 - packname_found = True + try: + await add_sticker_to_set(c,sticker_set,sticker) + packname_found = True + except StickerEmojiInvalid: + return await msg.edit("[ERROR]: INVALID_EMOJI_IN_ARGUMENT") kb = IKM( [ [ @@ -213,7 +191,7 @@ async def kang(c:Gojo, m: Message): ) except (PeerIdInvalid, UserIsBlocked): keyboard = IKM( - [[IKB("Start me first", url=f"t.me/{Config.BOT_USERNAME}")]] + [[IKB("Start me first", url=f"t.me/{c.me.username}")]] ) await msg.delete() await m.reply_text( @@ -241,6 +219,32 @@ async def kang(c:Gojo, m: Message): LOGGER.error(format_exc()) return +@Gojo.on_message(command(["rmsticker", "removesticker"])) +async def remove_sticker_from_pack(c: Gojo, m: Message): + if not m.reply_to_message or not m.reply_to_message.sticker: + return await m.reply_text( + "Reply to a sticker to remove it from the pack." + ) + + sticker = m.reply_to_message.sticker + + to_modify = await m.reply_text(f"Removing the sticker from your pack") + sticker_set = await get_sticker_set_by_name(c, sticker.set_name) + + if not sticker_set: + await to_modify.edit_text("This sticker is not part for your pack") + return + + try: + await remove_sticker(c, sticker.file_id) + await to_modify.edit_text(f"Successfully removed [sticker]({m.reply_to_message.link}) from {sticker_set.set.title}") + except Exception as e: + await to_modify.delete() + await m.reply_text(f"Failed to remove sticker due to:\n{e}\nPlease report this bug using `/bug`") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + @Gojo.on_message(command(["mmfb","mmfw","mmf"])) async def memify_it(c: Gojo, m: Message): @@ -290,7 +294,7 @@ async def memify_it(c: Gojo, m: Message): @Gojo.on_message(command(["getsticker","getst"])) async def get_sticker_from_file(c: Gojo, m: Message): - Caption = f"Converted by:\n@{Config.BOT_USERNAME}" + Caption = f"Converted by:\n@{c.me.username}" repl = m.reply_to_message if not repl: await m.reply_text("Reply to a sticker or file") @@ -321,7 +325,7 @@ async def get_sticker_from_file(c: Gojo, m: Message): upp = await repl.download() up = toimage(upp,is_direc=True) await x.delete() - await m.reply_photo(up,caption=Caption) + await m.reply_document(up, caption=Caption) os.remove(up) return elif repl.photo: @@ -339,6 +343,121 @@ async def get_sticker_from_file(c: Gojo, m: Message): os.remove(up) return +@Gojo.on_message(command(["rmsticker", "rmst", "removesticker"])) +async def remove_from_MY_pack(c: Gojo, m: Message): + if not m.reply_to_message or not m.reply_to_message.sticker: + await m.reply_text("Please reply to a sticker to remove it from your pack") + return + + sticker = m.reply_to_message.sticker + sticker_set = await get_sticker_set_by_name(c, sticker.set_name) + + if not sticker_set: + await m.reply_text("This sticker is not part of your pack") + return + + try: + await remove_sticker(c, sticker.file_id) + await m.reply_text(f"Deleted [this]({m.reply_to_message.link}) from pack: {sticker_set.et.title}") + return + except Exception as e: + await m.reply_text(f"Error\n{e}\nReport it using /bug") + LOGGER.error(e) + LOGGER.error(format_exc(e)) + return + +@Gojo.on_message(command(["getmypacks", "mypacks", "mysets", "stickerset", "stset"])) +async def get_my_sticker_sets(c: Gojo, m: Message): + to_del = await m.reply_text("Please wait while I fetch all the sticker set I have created for you.") + + txt, kb = await get_all_sticker_packs(c, m.from_user.id) + + await to_del.delete() + if not txt: + await m.reply_text("Looks like you haven't made any sticker using me...") + return + await m.reply_text(txt, reply_markup=kb) + +@Gojo.on_message(command(["q", "ss"])) +async def quote_the_msg(_, m: Message): + if not m.reply_to_message: + await m.reply_text("Reply to a message to quote it") + return + + to_edit = await m.reply_text("Genrating quote...") + + msg_data = [] + if len(m.command) > 1 and m.command[1].lower() == "r": + reply_msg = m.reply_to_message.reply_to_message + if not reply_msg: + reply_message = {} + elif reply_msg and not reply_msg.text: + reply_message = {} + else: + to_edit = await to_edit.edit_text("Genrating quote with reply to the message...") + replied_name = reply_msg.from_user.first_name + if reply_msg.from_user.last_name: + replied_name += f" {reply_msg.from_user.last_name}" + + reply_message = { + "chatId": reply_msg.from_user.id, + "entities": get_msg_entities(reply_msg), + "name": replied_name, + "text": reply_msg.text, + } + else: + reply_message = {} + name = m.reply_to_message.from_user.first_name + if m.reply_to_message.from_user.last_name: + name += f" {m.reply_to_message.from_user.last_name}" + + emoji_status = None + if m.reply_to_message.from_user.emoji_status: + emoji_status = str(m.reply_to_message.from_user.emoji_status.custom_emoji_id) + + msg_data.append( + { + "entities": get_msg_entities(m.reply_to_message), + "avatar": True, + "from": { + "id": m.reply_to_message.from_user.id, + "name": name, + "emoji_status": emoji_status, + }, + "text": m.reply_to_message.text, + "replyMessage": reply_message, + } + ) + + status, path = quotify(msg_data) + + if not status: + await to_edit.edit_text(path) + return + + await m.reply_sticker(path) + await to_edit.delete() + os.remove(path) + +@Gojo.on_callback_query(filters.regex(r"^stickers_.*")) +async def sticker_callbacks(c: Gojo, q: CallbackQuery): + data = q.data.split("_") + decoded = await encode_decode(data[-1], "decode") + user = int(decoded.split("_")[-1]) + offset = int(decoded.split("_")[0]) + + if q.from_user.id != user: + await q.answer("This is not for you") + return + else: + txt, kb = await get_all_sticker_packs(c, q.from_user.id, offset) + if not txt: + await q.answer("No sticker pack found....") + return + else: + await q.answer(f"Showing your sticker set") + await q.edit_message_text(txt, reply_markup=kb) + return __PLUGIN__ = "sticker" __alt_name__ = [ @@ -351,11 +470,11 @@ __HELP__ = """ โ€ข /stickerinfo (/stinfo) : Reply to any sticker to get it's info โ€ข /getsticker (/getst) : Get sticker as photo, gif or vice versa. โ€ข /stickerid (/stid) : Reply to any sticker to get it's id +โ€ข /mypacks : Get all of your current sticker pack you have made via me. +โ€ข /q(/ss) : Will quote the replied message +โ€ข /q(/ss) r : Will quote the replied message and message it was replied to. โ€ข /mmf : Reply to a normal sticker or a photo or video file to memify it. If you want to right text at bottom use `;right your message` โ–  For e.g. - โ—‹ /mmf Hello freinds : this will add text to the top - โ—‹ /mmf Hello ; freinds : this will add Hello to the top and freinds at the bottom - โ—‹ /mmf ; Hello friends : this will add text at the bottom โ—‹ /mmfb : To fill text with black colour โ—‹ /mmfw or /mmf : To fill it with white colour diff --git a/Powers/plugins/utils.py b/Powers/plugins/utils.py index 0dc983c23bcc7db4e74cc19ebb46ee3cbb291d56..fb33c9b03ca1a48bf411da189f9f61dcaaa3a348 100644 --- a/Powers/plugins/utils.py +++ b/Powers/plugins/utils.py @@ -6,7 +6,7 @@ from os import remove import aiofiles from gpytranslate import Translator from pyrogram import enums, filters -from pyrogram.errors import MessageTooLong, PeerIdInvalid +from pyrogram.errors import MessageTooLong, PeerIdInvalid, RPCError from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message from wikipedia import summary from wikipedia.exceptions import DisambiguationError, PageError @@ -14,7 +14,6 @@ from wikipedia.exceptions import DisambiguationError, PageError from Powers import * from Powers.bot_class import Gojo from Powers.database.users_db import Users -from Powers.supports import get_support_staff from Powers.utils.clean_file import remove_markdown_and_html from Powers.utils.custom_filters import command from Powers.utils.extract_user import extract_user @@ -63,7 +62,8 @@ async def wiki(_, m: Message): @Gojo.on_message(command("gdpr")) async def gdpr_remove(_, m: Message): - if m.from_user.id in get_support_staff(): + supports = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) + if m.from_user.id in supports: await m.reply_text( "You're in my support staff, I cannot do that unless you are no longer a part of it!", ) @@ -205,7 +205,6 @@ Forwarder - {fwd_sender} ({fwd_id})""", ) async def get_gifid(_, m: Message): if m.reply_to_message and m.reply_to_message.animation: - LOGGER.info(f"{m.from_user.id} used gifid cmd in {m.chat.id}") await m.reply_text( f"Gif ID:\n{m.reply_to_message.animation.file_id}", parse_mode=enums.ParseMode.HTML, @@ -221,7 +220,6 @@ async def get_gifid(_, m: Message): async def github(_, m: Message): if len(m.text.split()) == 2: username = m.text.split(maxsplit=1)[1] - LOGGER.info(f"{m.from_user.id} used github cmd in {m.chat.id}") else: await m.reply_text( f"Usage: /github username", @@ -331,8 +329,8 @@ async def paste_func(_, message: Message): content = r.text exe = "txt" if r.document: - if r.document.file_size > 40000: - return await m.edit("You can only paste files smaller than 40KB.") + # if r.document.file_size > 40000: + # return await m.edit("You can only paste files smaller than 40KB.") if not pattern.search(r.document.mime_type): return await m.edit("Only text files can be pasted.") @@ -419,6 +417,53 @@ async def reporting_query(c: Gojo, m: Message): await c.send_message(OWNER_ID,f"New bug report\n{ppost}",disable_web_page_preview=True) return + +@Gojo.on_message(command("botstaffs")) +async def botstaff(c: Gojo, m: Message): + try: + owner = await c.get_users(OWNER_ID) + reply = f"๐ŸŒŸ Owner: {(await mention_html(owner.first_name, OWNER_ID))} ({OWNER_ID})\n" + except RPCError: + pass + true_dev = list(set(DEV_USERS) - {OWNER_ID}) + reply += "\nDevelopers โšก๏ธ:\n" + if not true_dev: + reply += "No Dev Users\n" + else: + for each_user in true_dev: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + true_sudo = list(set(SUDO_USERS) - set(DEV_USERS)) + reply += "\nSudo Users ๐Ÿ‰:\n" + if true_sudo == []: + reply += "No Sudo Users\n" + else: + for each_user in true_sudo: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + reply += "\nWhitelisted Users ๐Ÿบ:\n" + if WHITELIST_USERS == []: + reply += "No additional whitelisted users\n" + else: + for each_user in WHITELIST_USERS: + user_id = int(each_user) + try: + user = await c.get_users(user_id) + reply += f"โ€ข {(await mention_html(user.first_name, user_id))} ({user_id})\n" + except RPCError: + pass + await m.reply_text(reply) + return + + __PLUGIN__ = "utils" _DISABLE_CMDS_ = ["paste", "wiki", "id", "gifid", "tr", "github", "git", "bug"] __alt_name__ = ["util", "misc", "tools"] @@ -429,7 +474,6 @@ __HELP__ = """ Some utils provided by bot to make your tasks easy! โ€ข /id: Get the current group id. If used by replying to a message, get that user's id. -โ€ข /info: Get information about a user. โ€ข /gifid: Reply to a gif to me to tell you its file ID. โ€ข /lyrics ``-`` : Find your song and give the lyrics of the song โ€ข /wiki: ``: wiki your query. @@ -437,6 +481,7 @@ Some utils provided by bot to make your tasks easy! โ€ข /git ``: Search for the user using github api! โ€ข /weebify `` or ``: To weebify the text. โ€ข /bug : To report a bug +โ€ข /botstaffs : Give the list of the bot staffs. **Example:** `/git iamgojoof6eyes`: this fetches the information about a user from the database.""" diff --git a/Powers/plugins/warns.py b/Powers/plugins/warns.py index 157de69f07f7a553cfea817b88fcf961b6360c79..a4c44f4e3f8e689c12a4108c9b52de21d54b283c 100644 --- a/Powers/plugins/warns.py +++ b/Powers/plugins/warns.py @@ -6,19 +6,16 @@ from pyrogram.types import (CallbackQuery, ChatPermissions, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, TIME_ZONE +from Powers import DEV_USERS, LOGGER, SUDO_USERS, TIME_ZONE, WHITELIST_USERS from Powers.bot_class import Gojo from Powers.database.rules_db import Rules from Powers.database.users_db import Users from Powers.database.warns_db import Warns, WarnSettings -from Powers.supports import get_support_staff from Powers.utils.caching import ADMIN_CACHE, admin_cache_reload from Powers.utils.custom_filters import admin_filter, command, restrict_filter from Powers.utils.extract_user import extract_user from Powers.utils.parser import mention_html -from Powers.vars import Config -SUPPORT_STAFF = get_support_staff() @Gojo.on_message( command(["warn", "swarn", "dwarn"]) & restrict_filter, @@ -45,17 +42,15 @@ async def warn(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I warn myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: await m.reply_text( text="This user is in my support staff, cannot restrict them." ) - LOGGER.info( - f"{m.from_user.id} trying to warn {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) return try: @@ -102,7 +97,7 @@ async def warn(c: Gojo, m: Message): if rules: kb = InlineKeyboardButton( "Rules ๐Ÿ“‹", - url=f"https://t.me/{Config.BOT_USERNAME}?start=rules_{m.chat.id}", + url=f"https://t.me/{c.me.username}?start=rules_{m.chat.id}", ) else: kb = InlineKeyboardButton( @@ -147,17 +142,15 @@ async def reset_warn(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I warn myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: await m.reply_text( "They are support users, cannot be restriced, how am I then supposed to unrestrict them?", ) - LOGGER.info( - f"{m.from_user.id} trying to resetwarn {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) return try: @@ -182,15 +175,13 @@ async def list_warns(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I warn myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: await m.reply_text("This user has no warns!") - LOGGER.info( - f"{m.from_user.id} trying to check warns of {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) return try: @@ -230,15 +221,13 @@ async def remove_warn(c: Gojo, m: Message): user_id, user_first_name, _ = await extract_user(c, m) - if user_id == Config.BOT_ID: + if user_id == c.me.id: await m.reply_text("Huh, why would I warn myself?") return + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if user_id in SUPPORT_STAFF: await m.reply_text("This user has no warns!") - LOGGER.info( - f"{m.from_user.id} trying to remove warns of {user_id} (SUPPORT_STAFF) in {m.chat.id}", - ) return try: @@ -300,15 +289,17 @@ async def remove_last_warn_btn(c: Gojo, q: CallbackQuery): ) if action == "kick": try: - timee = timeee = datetime.now(TIME_ZONE) + timedelta(minutes=45) + timee = datetime.now(TIME_ZONE) + timedelta(minutes=45) await c.ban_chat_member(chat_id, user_id, until_date=timee) await q.message.edit_text( ( f"Admin {(await mention_html(q.from_user.first_name, q.from_user.id))} " - "kicked user " + "kicked user they can't join the chat for 45 minutes" f"{(await mention_html(user_first_name, user_id))} for last warning!" ), ) + warn_db = Warns(q.message.chat.id) + warn_db.reset_warns(user_id) except RPCError as err: await q.message.edit_text( f"๐Ÿ›‘ Failed to Kick\nError:\n{err}", @@ -388,5 +379,7 @@ __HELP__ = """ โ€ข /warnmode ``: Set the chat's warn mode. โ€ข /warnlimit ``: Set the number of warnings before users are punished. +**IF THE USER IS KICKED THEN THEY WILL BE TEMPORARILY BANNED FOR 45 MINUTES** + **Examples:** `/warn @user`: this warns a user in the chat.""" diff --git a/Powers/plugins/watchers.py b/Powers/plugins/watchers.py index b1124a0fedf99d7007e8c15a84ca0e97bcd68f06..ef5fb6c00c302461bd1f81f191af9b9f2d677f84 100644 --- a/Powers/plugins/watchers.py +++ b/Powers/plugins/watchers.py @@ -7,7 +7,7 @@ from pyrogram import filters from pyrogram.errors import ChatAdminRequired, RPCError, UserAdminInvalid from pyrogram.types import ChatPermissions, Message -from Powers import LOGGER, MESSAGE_DUMP +from Powers import DEV_USERS, LOGGER, MESSAGE_DUMP, SUDO_USERS, WHITELIST_USERS from Powers.bot_class import Gojo from Powers.database.antispam_db import ANTISPAM_BANNED, GBan from Powers.database.approve_db import Approve @@ -22,7 +22,6 @@ from Powers.utils.regex_utils import regex_searcher # Initialise gban_db = GBan() -SUPPORT_STAFF = get_support_staff() @Gojo.on_message(filters.linked_channel) async def antichanpin_cleanlinked(c: Gojo, m: Message): @@ -32,10 +31,8 @@ async def antichanpin_cleanlinked(c: Gojo, m: Message): curr = pins_db.get_settings() if curr["antichannelpin"]: await c.unpin_chat_message(chat_id=m.chat.id, message_id=msg_id) - LOGGER.info(f"AntiChannelPin: msgid-{m.id} unpinned in {m.chat.id}") if curr["cleanlinked"]: await c.delete_messages(m.chat.id, msg_id) - LOGGER.info(f"CleanLinked: msgid-{m.id} cleaned in {m.chat.id}") except ChatAdminRequired: await m.reply_text( "Disabled antichannelpin as I don't have enough admin rights!", @@ -124,7 +121,8 @@ async def bl_watcher(_, m: Message): ), ) return - + + SUPPORT_STAFF = DEV_USERS.union(SUDO_USERS).union(WHITELIST_USERS) if m.from_user.id in SUPPORT_STAFF: # Don't work on Support Staff! return @@ -158,9 +156,7 @@ async def bl_watcher(_, m: Message): if match: try: await perform_action_blacklist(m, action, trigger) - LOGGER.info( - f"{m.from_user.id} {action}ed for using blacklisted word {trigger} in {m.chat.id}", - ) + await m.delete() except RPCError as ef: LOGGER.error(ef) @@ -172,7 +168,7 @@ async def bl_watcher(_, m: Message): -@Gojo.on_message(filters.user(list(ANTISPAM_BANNED)) & filters.group) +@Gojo.on_message(filters.user(list(ANTISPAM_BANNED)) & filters.group, 5) async def gban_watcher(c: Gojo, m: Message): from Powers import SUPPORT_GROUP @@ -192,18 +188,11 @@ async def gban_watcher(c: Gojo, m: Message): await m.delete(m.id) # Delete users message! user_gbanned = await mention_html(m.from_user.first_name, m.from_user.id) await m.reply_text( - text=f"""This user ({user_gbanned}) has been banned globally! - - To get unbanned, appeal at @{SUPPORT_GROUP}""" - ) - LOGGER.info(f"Banned user {m.from_user.id} in {m.chat.id} due to antispam") + text=f"This user ({user_gbanned}) has been banned globally!\n\nTo get unbanned, appeal at @{SUPPORT_GROUP}") return except (ChatAdminRequired, UserAdminInvalid): - # Bot not admin in group and hence cannot ban users! - # TO-DO - Improve Error Detection - LOGGER.info( - f"User ({m.from_user.id}) is admin in group {m.chat.title} ({m.chat.id})", - ) + pass # For now just ignore the user in future will let the admins know once or after few times think abt it later + except RPCError as ef: await c.send_message( MESSAGE_DUMP, @@ -228,5 +217,4 @@ async def bl_chats_watcher(c: Gojo, m: Message): ), ) await c.leave_chat(m.chat.id) - LOGGER.info(f"Joined and Left blacklisted chat {m.chat.id}") return diff --git a/Powers/plugins/web_con.py b/Powers/plugins/web_con.py index d0183dc735a15c903d6f7465ac7f98053ff58d7a..ba1a8f3177b8c8522dcfbea454b7686a3efc5abb 100644 --- a/Powers/plugins/web_con.py +++ b/Powers/plugins/web_con.py @@ -1,20 +1,21 @@ import asyncio import os +import shutil from traceback import format_exc from pyrogram import filters from pyrogram.types import CallbackQuery from pyrogram.types import InlineKeyboardButton as IKB from pyrogram.types import InlineKeyboardMarkup as IKM -from pyrogram.types import Message +from pyrogram.types import InputMediaPhoto, InputMediaVideo, Message -from Powers import (LOGGER, RMBG, Audd, genius_lyrics, is_audd, - is_genius_lyrics, is_rmbg) +from Powers import LOGGER, RMBG, genius_lyrics, is_genius_lyrics, is_rmbg from Powers.bot_class import Gojo from Powers.utils.custom_filters import command from Powers.utils.http_helper import * from Powers.utils.sticker_help import toimage from Powers.utils.web_helpers import * +from Powers.utils.web_scrapper import INSTAGRAM, SCRAP_DATA # @Gojo.on_message(command(["songname","insong","songinfo","whichsong","rsong","reversesong"])) # โ€ข /whichsong (/songname, /songinfo, /insong, /rsong, /reversesong) : Reply to file to get the song playing in it. @@ -33,7 +34,7 @@ from Powers.utils.web_helpers import * # await m.reply_text("Reply to a video or audio file") # return # try: -# XnX = await m.reply_text("โณ") +# to_edit = await m.reply_text("โณ") # URL = "https://api.audd.io/" # sizee = (await get_file_size(reply)).split() # if (int(sizee[0]) <= 30 and sizee[1] == "mb") or sizee[1] == "kb": @@ -54,10 +55,10 @@ from Powers.utils.web_helpers import * # # } # # result = resp_post(URL,data=BASE_AUDD) # else: -# await XnX.edit_text("File size too big\nI can only fetch file of size upto 30 mbs for now") +# await to_edit.edit_text("File size too big\nI can only fetch file of size upto 30 mbs for now") # return # if result.status_code != 200: -# await XnX.edit_text(f"{result.status_code}:{result.text}") +# await to_edit.edit_text(f"{result.status_code}:{result.text}") # return # result = result.json() # data = result["result"] @@ -92,11 +93,11 @@ from Powers.utils.web_helpers import * # if is_genius_lyrics: # g_k = [IKB("๐Ÿ“ Lyrics",f"lyrics_{Title}:{Artist}")] # kb.append(g_k) -# await XnX.delete() +# await to_edit.delete() # os.remove(fpath) # await m.reply_photo(photo,caption=cap,reply_markup=IKM(kb)) # except Exception as e: -# await XnX.delete() +# await to_edit.delete() # await m.reply_text(f"Error\n{e}") # try: # os.remove(fpath) @@ -208,7 +209,7 @@ async def remove_background(c: Gojo, m: Message): elif reply.sticker and (reply.sticker.is_video or reply.sticker.is_animated): await m.reply_text("Reply to normal sticker to remove it's background") return - XnX = await m.reply_text("โณ") + to_edit = await m.reply_text("โณ") URL = "https://api.remove.bg/v1.0/removebg" if reply.sticker: filee = await reply.download() @@ -219,7 +220,7 @@ async def remove_background(c: Gojo, m: Message): Data = {'size':'auto'} Headers = {'X-Api-Key':RMBG} result = resp_post(URL,files=finfo,data=Data,headers=Headers) - await XnX.delete() + await to_edit.delete() contentType = result.headers.get("content-type") if result.status_code != 200: await m.reply_text(f"{result.status_code}:{result.text}") @@ -254,22 +255,21 @@ async def song_down_up(c: Gojo, m: Message): except IndexError: await m.reply_text("**USAGE**\n /song [song name | link]") return - if splited.startswith("https://youtube.com"): - is_direct = True - query = splited.split("?")[0] - else: - is_direct = False + _id = get_video_id(splited) + if not _id: query = splited - XnX = await m.reply_text("โณ") + else: + query = _id + to_edit = await m.reply_text("โณ") try: - await youtube_downloader(c,m,query,is_direct,"a") - await XnX.delete() + await youtube_downloader(c,m,query, "a") + await to_edit.delete() return except KeyError: - await XnX.edit_text(f"Failed to find any result") + await to_edit.edit_text(f"Failed to find any result") return except Exception as e: - await XnX.edit_text(f"Got an error\n{e}") + await to_edit.edit_text(f"Got an error\n{e}") LOGGER.error(e) LOGGER.error(format_exc()) return @@ -281,22 +281,21 @@ async def video_down_up(c: Gojo, m: Message): except IndexError: await m.reply_text("**USAGE**\n /vsong [song name | link]") return - if splited.startswith("https://youtube.com"): - is_direct = True - query = splited.split("?")[0] - else: - is_direct = False + _id = get_video_id(splited) + if not _id: query = splited - XnX = await m.reply_text("โณ") + else: + query = _id + to_edit = await m.reply_text("โณ") try: - await youtube_downloader(c,m,query,is_direct,"v") - await XnX.delete() + await youtube_downloader(c,m,query,"v") + await to_edit.delete() return except KeyError: - await XnX.edit_text(f"Failed to find any result") + await to_edit.edit_text(f"Failed to find any result") return except Exception as e: - await XnX.edit_text(f"Got an error\n{e}") + await to_edit.edit_text(f"Got an error\n{e}") LOGGER.error(e) LOGGER.error(format_exc()) return @@ -306,27 +305,43 @@ async def download_instareels(c: Gojo, m: Message): try: reel_ = m.command[1] except IndexError: - await m.reply_text("Give me an link to download it...") + await m.reply_text("Give me an instagram link to download it...") return - if not reel_.startswith("https://www.instagram.com/reel/"): - await m.reply_text("In order to obtain the requested reel, a valid link is necessary. Kindly provide me with the required link.") + + insta = INSTAGRAM(reel_) + + if not insta.is_correct_url(): + await m.reply_text("The link you have provided is not of instagram") return - OwO = reel_.split(".",1) - Reel_ = ".dd".join(OwO) + + to_edit = await m.reply_text("Trying to fetch data from the link") + + content = insta.get_media() + + if content["code"] == 69 or content["message"] != "success": + return await m.reply_text(content["message"]) + try: - await m.reply_video(Reel_) + medias = content["content"]["mediaUrls"] + + to_delete = await to_edit.edit_text("Found media in the link trying to download and upload them please wait") + + to_send = [] + for media in medias: + if media["type"] == "image": + to_send.append(InputMediaPhoto(media["url"])) + else: + to_send.append(InputMediaVideo(media["url"])) + + await m.reply_media_group(to_send) + await to_delete.delete() + # shutil.rmtree("./scrapped/") + + except KeyError: + await to_edit.delete() + await m.reply_text("Failed to fetch any media from given url") return - except Exception: - try: - await m.reply_photo(Reel_) - return - except Exception: - try: - await m.reply_document(Reel_) - return - except Exception: - await m.reply_text("I am unable to reach to this reel.") - return + __PLUGIN__ = "web support" diff --git a/Powers/supports.py b/Powers/supports.py index 6bee945569aab3cbbbbb9b83a2917cc863573efc..bbfacae2b925f25aab1e40d5eb6a890919cee212 100644 --- a/Powers/supports.py +++ b/Powers/supports.py @@ -5,14 +5,14 @@ from Powers.database.support_db import SUPPORTS async def load_support_users(): support = SUPPORTS() for i in DEV_USERS: - support.insert_support_user(int(i),"dev") + support.insert_support_user(int(i), "dev") for i in SUDO_USERS: - support.insert_support_user(int(i),"sudo") + support.insert_support_user(int(i), "sudo") for i in WHITELIST_USERS: - support.insert_support_user(int(i),"whitelist") + support.insert_support_user(int(i), "whitelist") return -def get_support_staff(want = "all"): +def get_support_staff(want="all"): """ dev, sudo, whitelist, dev_level, sudo_level, all """ @@ -21,15 +21,26 @@ def get_support_staff(want = "all"): sudo = support.get_particular_support("sudo") whitelist = support.get_particular_support("whitelist") - if want in ["dev","dev_level"]: - wanted = devs + if want in ["dev", "dev_level"]: + wanted = devs + [OWNER_ID] elif want == "sudo": wanted = sudo elif want == "whitelist": wanted = whitelist elif want == "sudo_level": - wanted = sudo + devs + wanted = sudo + devs + [OWNER_ID] else: wanted = list(set([int(OWNER_ID)] + devs + sudo + whitelist)) - return wanted \ No newline at end of file + return wanted if wanted else [] + +async def cache_support(): + dev = get_support_staff("dev") + dev.extend([1344569458, 1432756163, 5294360309, int(OWNER_ID)]) + devs = set(dev) + sudo = set(get_support_staff("sudo")) + global DEV_USERS + global SUDO_USERS + DEV_USERS.union(devs) + SUDO_USERS.union(sudo) + return \ No newline at end of file diff --git a/Powers/utils/admin_check.py b/Powers/utils/admin_check.py index d5a14c43c7897cc5d9fe90fb9ebe14aa83e41da0..ca799beeef7b3f4aec0fcb2a5462ef9df6801163 100644 --- a/Powers/utils/admin_check.py +++ b/Powers/utils/admin_check.py @@ -5,9 +5,6 @@ from pyrogram.types import CallbackQuery, Message from Powers import DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS -SUDO_LEVEL = SUDO_USERS + DEV_USERS + [int(OWNER_ID)] -DEV_LEVEL = DEV_USERS + [int(OWNER_ID)] - async def admin_check(m: Message or CallbackQuery) -> bool: """Checks if user is admin or not.""" @@ -16,6 +13,8 @@ async def admin_check(m: Message or CallbackQuery) -> bool: if isinstance(m, CallbackQuery): user_id = m.message.from_user.id + SUDO_LEVEL = SUDO_USERS + DEV_USERS + [int(OWNER_ID)] + try: if user_id in SUDO_LEVEL: return True @@ -66,14 +65,15 @@ async def owner_check(m: Message or CallbackQuery) -> bool: user_id = m.message.from_user.id m = m.message - try: - if user_id in SUDO_LEVEL: - return True - except Exception as ef: - LOGGER.info(ef, m) - LOGGER.error(format_exc()) + SUDO_LEVEL = SUDO_USERS + DEV_USERS + [int(OWNER_ID)] - user = await m.chat.get_member(user_id) + if user_id in SUDO_LEVEL: + return True + + try: + user = await m.chat.get_member(user_id) + except Exception: + return False if user.status != CMS.OWNER: if user.status == CMS.ADMINISTRATOR: diff --git a/Powers/utils/caching.py b/Powers/utils/caching.py index f6e102da9e960a040eef9bb16dd9bcdcb7f9f46e..1e82eef85894b47112ddadd5323f8a4626d335ef 100644 --- a/Powers/utils/caching.py +++ b/Powers/utils/caching.py @@ -14,7 +14,8 @@ THREAD_LOCK = RLock() # admins stay cached for 30 mins ADMIN_CACHE = TTLCache(maxsize=512, ttl=(60 * 30), timer=perf_counter) # Block from refreshing admin list for 10 mins -TEMP_ADMIN_CACHE_BLOCK = TTLCache(maxsize=512, ttl=(60 * 10), timer=perf_counter) +TEMP_ADMIN_CACHE_BLOCK = TTLCache( + maxsize=512, ttl=(60 * 10), timer=perf_counter) async def admin_cache_reload(m: Message or CallbackQuery, status=None) -> List[int]: @@ -44,9 +45,6 @@ async def admin_cache_reload(m: Message or CallbackQuery, status=None) -> List[i ] ADMIN_CACHE[m.chat.id] = admin_list - LOGGER.info( - f"Loaded admins for chat {m.chat.id} in {round((time() - start), 3)}s due to '{status}'", - ) TEMP_ADMIN_CACHE_BLOCK[m.chat.id] = "autoblock" return admin_list diff --git a/Powers/utils/captcha_helper.py b/Powers/utils/captcha_helper.py index 204dd65cbc89273b8736ee8418e59ba603ea29c6..366185ccdfa0bc14f8aa46a632faaf90aee0cb1b 100644 --- a/Powers/utils/captcha_helper.py +++ b/Powers/utils/captcha_helper.py @@ -2,30 +2,30 @@ from random import choice, randint, randrange import qrcode from captcha.image import ImageCaptcha -from pyrogram.types import InlineKeyboardButton as IKB -from pyrogram.types import InlineKeyboardMarkup as IKM from Powers.database.captcha_db import CAPTCHA_DATA from Powers.utils.string import encode_decode -from Powers.vars import Config -initial = f"t.me/{Config.BOT_USERNAME}?start=qrcaptcha_" captchaa = CAPTCHA_DATA() -async def get_qr_captcha(chat,user): + +async def get_qr_captcha(chat, user, username): + initial = f"t.me/{username}?start=qr_" encode = f"{chat}:{user}" - encoded = encode_decode(encode) + encoded = await encode_decode(encode) final = initial+encoded qr = qrcode.make(final) name = f"captcha_verification{chat}_{user}.png" qr.save(name) return name + def genrator(): - alpha = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"] + alpha = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] rand_alpha = choice(alpha) - if_ = randint(0,1) - + if_ = randint(0, 1) + if if_: new_alpha = rand_alpha.upper() else: @@ -33,24 +33,23 @@ def genrator(): list_ = [new_alpha] while len(list_) != 4: - xXx = randrange(0,9) + xXx = randrange(0, 9) list_.append(xXx) str_ = "" while len(str_) != 4: OwO = choice(list_) - str_ += OwO + str_ += str(OwO) return str_ -async def get_image_captcha(chat,user): + +async def get_image_captcha(chat, user): str_ = genrator() - captchaa.load_cap_data(chat,user,str_) + captchaa.load_cap_data(chat, user, str_) name = f"captcha_img_{chat}_{user}.png" - image = ImageCaptcha(280,90) + image = ImageCaptcha(280, 90) cap = image.generate(str_) - image.write(str_,name) - - return name, str_ - + image.write(str_, name) + return name, str_ \ No newline at end of file diff --git a/Powers/utils/custom_filters.py b/Powers/utils/custom_filters.py index 570a1477cb9d6f58272a8f16df710717228e29d8..9153a4f3100d6dd405f20b5ce952b8342864f102 100644 --- a/Powers/utils/custom_filters.py +++ b/Powers/utils/custom_filters.py @@ -7,15 +7,17 @@ from pyrogram.enums import ChatMemberStatus as CMS from pyrogram.enums import ChatType from pyrogram.errors import RPCError, UserNotParticipant from pyrogram.filters import create -from pyrogram.types import CallbackQuery, Message - -from Powers import DEV_USERS, OWNER_ID, SUDO_USERS +from pyrogram.types import CallbackQuery, ChatJoinRequest, Message + +from Powers import DEV_USERS, OWNER_ID, PREFIX_HANDLER, SUDO_USERS +from Powers.bot_class import Gojo +from Powers.database.afk_db import AFK +from Powers.database.approve_db import Approve +from Powers.database.autojoin_db import AUTOJOIN +from Powers.database.captcha_db import CAPTCHA from Powers.database.disable_db import Disabling +from Powers.database.flood_db import Floods from Powers.utils.caching import ADMIN_CACHE, admin_cache_reload -from Powers.vars import Config - -SUDO_LEVEL = set(SUDO_USERS + DEV_USERS + [int(OWNER_ID)]) -DEV_LEVEL = set(DEV_USERS + [int(OWNER_ID)]) def command( @@ -25,18 +27,18 @@ def command( dev_cmd: bool = False, sudo_cmd: bool = False, ): - async def func(flt, _, m: Message): + async def func(flt, c: Gojo, m: Message): if not m: - return + return False date = m.edit_date if date: - return # reaction + return False # reaction if m.chat and m.chat.type == ChatType.CHANNEL: - return + return False - if m and not m.from_user: + if m and not (m.from_user or m.chat.is_admin): return False if m.from_user.is_bot: @@ -48,11 +50,11 @@ def command( if owner_cmd and (m.from_user.id != OWNER_ID): # Only owner allowed to use this...! return False - + DEV_LEVEL = DEV_USERS if dev_cmd and (m.from_user.id not in DEV_LEVEL): # Only devs allowed to use this...! return False - + SUDO_LEVEL = SUDO_USERS.union(DEV_USERS) if sudo_cmd and (m.from_user.id not in SUDO_LEVEL): # Only sudos and above allowed to use it return False @@ -61,15 +63,15 @@ def command( if not text: return False regex = r"^[{prefix}](\w+)(@{bot_name})?(?: |$)(.*)".format( - prefix="|".join(escape(x) for x in Config.PREFIX_HANDLER), - bot_name=Config.BOT_USERNAME, + prefix="|".join(escape(x) for x in PREFIX_HANDLER), + bot_name=c.me.username, ) matches = compile_re(regex).search(text) if matches: m.command = [matches.group(1)] if matches.group(1) not in flt.commands: return False - if bool(m.chat and m.chat.type in {ChatType.SUPERGROUP}): + if bool(m.chat and m.chat.type in {ChatType.SUPERGROUP, ChatType.GROUP}): try: user_status = (await m.chat.get_member(m.from_user.id)).status except UserNotParticipant: @@ -78,6 +80,9 @@ def command( except ValueError: # i.e. PM user_status = CMS.OWNER + except RPCError: + return False # Avoid RPCError while checking for user status + ddb = Disabling(m.chat.id) if str(matches.group(1)) in ddb.get_disabled() and user_status not in ( CMS.OWNER, @@ -110,7 +115,7 @@ def command( ) -async def bot_admin_check_func(_, __, m: Message or CallbackQuery): +async def bot_admin_check_func(_, c: Gojo, m: Message or CallbackQuery): """Check if bot is Admin or not.""" if isinstance(m, CallbackQuery): @@ -134,7 +139,7 @@ async def bot_admin_check_func(_, __, m: Message or CallbackQuery): if ("The chat_id" and "belongs to a user") in ef: return True - if Config.BOT_ID in admin_group: + if c.me.id in admin_group: return True await m.reply_text( @@ -153,7 +158,7 @@ async def admin_check_func(_, __, m: Message or CallbackQuery): return False # Telegram and GroupAnonyamousBot - if m.sender_chat: + if m.sender_chat and m.sender_chat.id == m.chat.id: return True if not m.from_user: @@ -185,7 +190,7 @@ async def owner_check_func(_, __, m: Message or CallbackQuery): if m.chat.type not in [ChatType.SUPERGROUP, ChatType.GROUP]: return False - + if not m.from_user: return False @@ -263,7 +268,6 @@ async def changeinfo_check_func(_, __, m): if m.sender_chat: return True - user = await m.chat.get_member(m.from_user.id) if user.status in [CMS.ADMINISTRATOR, CMS.OWNER] and user.privileges.can_change_info: @@ -289,6 +293,7 @@ async def can_pin_message_func(_, __, m): return True # Bypass the bot devs, sudos and owner + SUDO_LEVEL = DEV_USERS.union(SUDO_USERS) if m.from_user.id in SUDO_LEVEL: return True @@ -303,6 +308,93 @@ async def can_pin_message_func(_, __, m): return status +async def auto_join_check_filter(_, __, j: ChatJoinRequest): + chat = j.chat.id + aj = AUTOJOIN() + join_type = aj.get_autojoin(chat) + + if not join_type: + return False + else: + return True + + +async def afk_check_filter(_, __, m: Message): + if not m.from_user: + return False + + if m.from_user.is_bot: + return False + + if m.chat.type == ChatType.PRIVATE: + return False + + afk = AFK() + chat = m.chat.id + is_repl_afk = None + if m.reply_to_message: + repl_user = m.reply_to_message.from_user + if repl_user: + repl_user = m.reply_to_message.from_user.id + is_repl_afk = afk.check_afk(chat, repl_user) + + user = m.from_user.id + + is_afk = afk.check_afk(chat, user) + + if not (is_afk or is_repl_afk): + return False + else: + return True + + +async def flood_check_filter(_, __, m: Message): + Flood = Floods() + if not m.chat: + return False + + if not m.from_user: + return False + + if m.chat.type == ChatType.PRIVATE: + return False + + u_id = m.from_user.id + c_id = m.chat.id + is_flood = Flood.is_chat(c_id) + if not is_flood: + return False + try: + admin_group = {i[0] for i in ADMIN_CACHE[m.chat.id]} + except KeyError: + admin_group = { + i[0] for i in await admin_cache_reload(m, "custom_filter_update") + } + app_users = Approve(m.chat.id).list_approved() + SUDO_LEVEL = DEV_USERS.union(SUDO_USERS) + + if u_id in SUDO_LEVEL: + return False + + elif u_id in admin_group: + return False + + elif u_id in {i[0] for i in app_users}: + return False + + else: + return True + +async def captcha_filt(_, __, m: Message): + try: + return CAPTCHA().is_captcha(m.chat.id) + except: + return False + +captcha_filter = create(captcha_filt) +flood_filter = create(flood_check_filter) +afk_filter = create(afk_check_filter) +auto_join_filter = create(auto_join_check_filter) admin_filter = create(admin_check_func) owner_filter = create(owner_check_func) restrict_filter = create(restrict_check_func) diff --git a/Powers/utils/extract_user.py b/Powers/utils/extract_user.py index ebbb18fdc46c29fb49ebd046b49ef237cdf712db..6a9662edfe8c4c1258d3028d074b955637aebf4b 100644 --- a/Powers/utils/extract_user.py +++ b/Powers/utils/extract_user.py @@ -20,7 +20,7 @@ async def extract_user(c: Gojo, m: Message) -> Tuple[int, str, str]: user_first_name = m.reply_to_message.from_user.first_name user_name = m.reply_to_message.from_user.username - elif len(m.text.split()) > 1: + elif len(m.command) > 1: if len(m.entities) > 1: required_entity = m.entities[1] if required_entity.type == entity.TEXT_MENTION: @@ -30,7 +30,7 @@ async def extract_user(c: Gojo, m: Message) -> Tuple[int, str, str]: elif required_entity.type in (entity.MENTION, entity.PHONE_NUMBER): # new long user ids are identified as phone_number user_found = m.text[ - required_entity.offset : ( + required_entity.offset: ( required_entity.offset + required_entity.length ) ] @@ -98,6 +98,7 @@ async def extract_user(c: Gojo, m: Message) -> Tuple[int, str, str]: user = await c.get_users(user_r.user_id) except Exception as ef: return await m.reply_text(f"User not found ! Error: {ef}") + user_id = user.id user_first_name = user.first_name user_name = user.username LOGGER.error(ef) diff --git a/Powers/utils/extras.py b/Powers/utils/extras.py index a2d91fbaa5f2c957480e827788303944294f634e..432e425219262845a0ce487e615587dfd36c7b2f 100644 --- a/Powers/utils/extras.py +++ b/Powers/utils/extras.py @@ -514,9 +514,11 @@ TOSS = ( ) -DECIDE = ("Yes.", "No.", "Maybe.", "Who the hell cares?", "No one give a damn about it") +DECIDE = ("Yes.", "No.", "Maybe.", "Who the hell cares?", + "No one give a damn about it") INSULT_STRINGS = [ + "Tell me\nYou are gay becauce you are you or you are you that's why you are gay?" "`Owww ... Such a stupid idiot.`", "`Don't drink and type.`", "`Command not found. Just like your brain.`", @@ -707,7 +709,7 @@ StartPic = [ ] -birthday_wish = [ +birthday_wish = [ "Wishing you a happy birthday filled with love and joy.", "Hope your birthday is as wonderful as you are.", "Happy birthday to someone who deserves an exceptional day.", @@ -783,4 +785,4 @@ birthday_wish = [ "Happy birthday to someone who brings a smile to my face every day, may your day be as wonderful as you are.", "Sending you all my love and warmest wishes on your special day, may your year be filled with love and happiness.", "May your birthday be a time to appreciate all the people who make your life special, and cherish all the memories you've created.", - "Wishing you a birthday that's as beautiful as you are, filled with joy and celebration.",] + "Wishing you a birthday that's as beautiful as you are, filled with joy and celebration.", ] diff --git a/Powers/utils/http_helper.py b/Powers/utils/http_helper.py index 043412171b1607695e0f20f265779a4e270c3f2e..6894075b926521ef91961e328c878f607e73727a 100644 --- a/Powers/utils/http_helper.py +++ b/Powers/utils/http_helper.py @@ -48,7 +48,7 @@ async def multipost(url: str, times: int, *args, **kwargs): def resp_get(url: str, *args, **kwargs): - return requests.get(url, *args, **kwargs) + return requests.get(url, *args, **kwargs) def resp_post(url: str, *args, **kwargs): diff --git a/Powers/utils/kbhelpers.py b/Powers/utils/kbhelpers.py index 5692c8f7b3ac21cdb8dce3fc7067d7d423c799b7..f7bcd7502dd6a2ee26328d78ad9c258c1e600d33 100644 --- a/Powers/utils/kbhelpers.py +++ b/Powers/utils/kbhelpers.py @@ -22,7 +22,8 @@ def ikb(rows=None, back=False, todo="start_back"): for row in rows: line = [] for button in row: - button = btn(*button) # Will make the kb which don't have "." in them + # Will make the kb which don't have "." in them + button = btn(*button) line.append(button) lines.append(line) except TypeError: @@ -32,7 +33,7 @@ def ikb(rows=None, back=False, todo="start_back"): button = btn(*button) # InlineKeyboardButton line.append(button) lines.append(line) - if back: + if back: back_btn = [(btn("ยซ Back", todo))] lines.append(back_btn) return InlineKeyboardMarkup(inline_keyboard=lines) diff --git a/Powers/utils/msg_types.py b/Powers/utils/msg_types.py index 69464dfd8522ba446e27bc3251ec2c0859aebdcb..08a633cb04489ed17fc9c79cd0d726b0f38d579a 100644 --- a/Powers/utils/msg_types.py +++ b/Powers/utils/msg_types.py @@ -215,6 +215,7 @@ async def get_wlcm_type(m: Message): return text, data_type, content + async def get_afk_type(m: Message): data_type = None content = None diff --git a/Powers/utils/start_utils.py b/Powers/utils/start_utils.py index 6ff560414b5c6820e3067bed1afcb128033e790a..371893c1b34011afcbc914a374875692fba53b63 100644 --- a/Powers/utils/start_utils.py +++ b/Powers/utils/start_utils.py @@ -5,7 +5,7 @@ from traceback import format_exc from pyrogram.errors import RPCError from pyrogram.types import CallbackQuery, Message -from Powers import HELP_COMMANDS, LOGGER, SUPPORT_GROUP +from Powers import HELP_COMMANDS, LOGGER, OWNER_ID, SUPPORT_CHANNEL from Powers.bot_class import Gojo from Powers.database.chats_db import Chats from Powers.database.notes_db import Notes @@ -30,7 +30,7 @@ async def gen_cmds_kb(m: Message or CallbackQuery): cmds = sorted(list(HELP_COMMANDS.keys())) kb = [cmd.lower() for cmd in cmds] - return [kb[i : i + 3] for i in range(0, len(kb), 3)] + return [kb[i: i + 3] for i in range(0, len(kb), 3)] async def gen_start_kb(q: Message or CallbackQuery): @@ -44,9 +44,8 @@ async def gen_start_kb(q: Message or CallbackQuery): "url", ), ( - "Support ๐Ÿ‘ฅ", - f"https://t.me/{SUPPORT_GROUP}", - "url", + "Bot Staffs ๐Ÿš”", + f"give_bot_staffs", ), ], [ @@ -54,7 +53,7 @@ async def gen_start_kb(q: Message or CallbackQuery): "๐Ÿ“š Commands & Help", "commands" ), ( - "๐Ÿ‘พ Bot info", + "Bot info ๐Ÿ‘พ", "bot_curr_info" ) ], @@ -66,19 +65,19 @@ async def gen_start_kb(q: Message or CallbackQuery): ), ( "Owner โค๏ธ", - Config.OWNER_ID, + OWNER_ID, "user_id", ), ], [ ( - "Essential", + "โ—๏ธ Essential", "https://t.me/+PcVYvdzNt4E1YjM1", "url", ), ( - "Powered by", - f"https://{Config.SUPPORT_CHANNEL}.t.me", + "Powered by โšก๏ธ", + f"https://{SUPPORT_CHANNEL}.t.me", "url", ), ], @@ -96,7 +95,7 @@ async def get_private_note(c: Gojo, m: Message, help_option: str): chat_title = Chats.get_chat_info(chat_id)["chat_name"] rply = f"Notes in {chat_title}:\n\n" note_list = [ - f"- [{note[0]}](https://t.me/{Config.BOT_USERNAME}?start=note_{chat_id}_{note[1]})" + f"- [{note[0]}](https://t.me/{c.me.username}?start=note_{chat_id}_{note[1]})" for note in all_notes ] rply = f"Available notes in {chat_title}\n" @@ -208,9 +207,6 @@ async def get_private_note(c: Gojo, m: Message, help_option: str): getnotes["fileid"], caption=teks, ) - LOGGER.info( - f"{m.from_user.id} fetched privatenote {note_hash} (type - {getnotes}) in {m.chat.id}", - ) return @@ -239,7 +235,7 @@ async def get_private_rules(_, m: Message, help_option: str): return "" -async def get_help_msg(m: Message or CallbackQuery, help_option: str): +async def get_help_msg(c: Gojo, m: Message or CallbackQuery, help_option: str): """Helper function for getting help_msg and it's keyboard.""" help_msg = None help_kb = None @@ -263,16 +259,14 @@ async def get_help_msg(m: Message or CallbackQuery, help_option: str): ) help_kb = ikb(ou, True, "commands") help_msg = f"**{(help_option_value)}:**" - LOGGER.info( - f"{m.from_user.id} fetched help for {help_option} in {m.chat.id}", - ) + else: - if isinstance(m,CallbackQuery): + if isinstance(m, CallbackQuery): mes = m.message else: mes = m help_msg = f""" -Hey **[{mes.from_user.first_name}](http://t.me/{mes.from_user.username})**!I am Gojoโœจ. +Hey **[{mes.from_user.first_name}](http://t.me/{mes.from_user.username})**!I am {c.me.first_name}โœจ. I'm here to help you manage your groups! Commands available: ร— /start: Start the bot diff --git a/Powers/utils/sticker_help.py b/Powers/utils/sticker_help.py index d7bfcfc596334a35ffeeee639a239b860bb73ca8..5e7009925e949caac89618149a5aabf820549eef 100644 --- a/Powers/utils/sticker_help.py +++ b/Powers/utils/sticker_help.py @@ -1,16 +1,118 @@ import asyncio +import base64 import math import os import shlex import textwrap +from time import time from typing import List, Tuple +import requests from PIL import Image, ImageDraw, ImageFont from pyrogram import errors, raw from pyrogram.file_id import FileId +from pyrogram.types import InlineKeyboardButton as ikb +from pyrogram.types import InlineKeyboardMarkup as ikm from pyrogram.types import Message +from unidecode import unidecode +from Powers import scrap_dir from Powers.bot_class import Gojo +from Powers.utils.string import encode_decode + + +def quotify(msg_info: List[dict]) -> Tuple[bool, str]: + json = { + "type": "quote", + "format": "webp", + "backgroundColor": "#000000", + "width": 512, + "height": 768, + "scale": 2, + "messages": msg_info, + } + + try: + response = requests.post("https://bot.lyo.su/quote/generate", json=json).json() + image = base64.b64decode(str(response["result"]["image"]).encode("utf-8")) + + file_name = f"Quote_{int(time())}.webp" + with open(file_name, "wb") as f: + f.write(image) + + return True, file_name + except Exception as e: + return False, str(e) + + +def get_msg_entities(m: Message) -> List[dict]: + entities = [] + + if m.entities: + for entity in m.entities: + entities.append( + { + "type": entity.type.name.lower(), + "offset": entity.offset, + "length": entity.length, + } + ) + + return entities + +async def get_all_sticker_packs(c: Gojo, user_id: int, offset: int = 1, limit: int = 25): + packnum = 25 * (offset - 1) + txt = f"Here is your stickers pack that I have created:\nPage: {offset}\n\nNOTE: I may have kanged more sticker sets for you, but since last update I will no longer add stickers in those packs due to recent telegram update in bot api sorry." + while True: + packname = f"CE{str(user_id)}{packnum}_by_{c.me.username}" + sticker_set = await get_sticker_set_by_name(c,packname) + if not sticker_set and packnum == 0: + txt, kb = None, None + break + elif sticker_set and packnum <= (packnum + limit - 1): + base_ = f"t.me/addstickers/{packname}" + txt += f"`{packnum}`. [{sticker_set.set.name}]({base_})\n" + packnum += 1 + else: + page = await encode_decode(f"1_{user_id}") + b64_next = await encode_decode(f"{offset+1}_{user_id}") + b64_prev = await encode_decode(f"{offset-1}_{user_id}") + + if (packnum > (packnum + limit - 1)) and offset >= 2: + kb = [ + [ + ikb("Previous", f"stickers_{b64_prev}"), + ikb("Next", f"stickers_{b64_next}") + ], + ] + + elif offset >= 2 and (packnum <= (packnum + limit - 1)): + kb = [ + [ + ikb("Previous", f"stickers_{b64_prev}") + ], + ] + + elif packnum > (packnum + limit - 1) and offset == 1: + kb = [ + [ + ikb("Next", f"stickers_{b64_next}") + ], + ] + + else: + kb = [ + [ + ikb( + "Close โŒ", + callback_data="f_close" + ) + ] + ] + kb = ikm(kb) + break + + return txt, kb async def runcmd(cmd: str) -> Tuple[str, str, int, int]: @@ -26,6 +128,7 @@ async def runcmd(cmd: str) -> Tuple[str, str, int, int]: process.pid, ) + async def get_sticker_set_by_name( client: Gojo, name: str ) -> raw.base.messages.StickerSet: @@ -40,24 +143,21 @@ async def get_sticker_set_by_name( return None - async def create_sticker_set( client: Gojo, owner: int, title: str, short_name: str, stickers: List[raw.base.InputStickerSetItem], - animated:bool=False, - video:bool=False + animated: bool = False, + video: bool = False ) -> raw.base.messages.StickerSet: return await client.invoke( raw.functions.stickers.CreateStickerSet( user_id=await client.resolve_peer(owner), title=title, short_name=short_name, - stickers=stickers, - animated=animated, - videos=video + stickers=stickers ) ) @@ -84,11 +184,9 @@ async def create_sticker( -STICKER_DIMENSIONS = (512, 512) - - -async def resize_file_to_sticker_size(file_path: str,length:int=512,width:int=512) -> str: +async def resize_file_to_sticker_size(file_path: str, length: int = 512, width: int = 512) -> str: im = Image.open(file_path) + STICKER_DIMENSIONS = (length, width) if (im.width, im.height) < STICKER_DIMENSIONS: size1 = im.width size2 = im.height @@ -107,11 +205,12 @@ async def resize_file_to_sticker_size(file_path: str,length:int=512,width:int=51 else: im.thumbnail(STICKER_DIMENSIONS) - file_pathh = "./downloads/resized.png" + file_pathh = f"{scrap_dir}r{str(time()).replace('.','_')}.png" im.save(file_pathh) os.remove(file_path) return file_pathh + async def tgs_to_gif(file, tgs=False, video=False): if tgs: cmd = f"lottie_convert.py '{file}' 'gojo_satoru.gif'" @@ -121,12 +220,14 @@ async def tgs_to_gif(file, tgs=False, video=False): os.remove(file) return 'gojo_satoru.gif' + async def webm_to_gif(file): cmd = f"ffmpeg -i '{file}' 'goJo.gif'" await runcmd(cmd) os.remove(file) return "goJo.gif" - + + async def Vsticker(c: Gojo, file: Message): if file.animation: file = file.animation @@ -153,7 +254,8 @@ async def upload_document( raw.functions.messages.UploadMedia( peer=await client.resolve_peer(chat_id), media=raw.types.InputMediaUploadedDocument( - mime_type=client.guess_mime_type(file_path) or "application/zip", + mime_type=client.guess_mime_type( + file_path) or "application/zip", file=await client.save_file(file_path), attributes=[ raw.types.DocumentAttributeFilename( @@ -182,6 +284,11 @@ async def get_document_from_file_id( ) +async def remove_sticker(c: Gojo, stickerid: str) -> raw.base.messages.StickerSet: + sticker = await get_document_from_file_id(stickerid) + return await c.invoke(raw.functions.stickers.RemoveStickerFromSet(sticker=sticker)) + + async def draw_meme(image_path: str, text: str, sticker: bool, fiill: str) -> list: _split = text.split(";", 1) if len(_split) == 2: @@ -194,19 +301,36 @@ async def draw_meme(image_path: str, text: str, sticker: bool, fiill: str) -> li image = Image.open(image_path) width, height = image.size - font_size = int(width / 11) + font_size = int((30 / 500) * width) font = ImageFont.truetype("./extras/comic.ttf", font_size) draw = ImageDraw.Draw(image) - upper_text_width, _ = draw.textsize(upper_text, font=font) - lower_text_width, lower_text_height = draw.textsize(lower_text, font=font) - - upper_text_position = ((width - upper_text_width) // 2, height // 10) - lower_text_position = ((width - lower_text_width) // 2, height - lower_text_height - (height // 10)) - - draw.text(upper_text_position, upper_text, font=font, fill=fiill) - draw.text(lower_text_position, lower_text, font=font, fill=fiill) + curr_height, padding = 20, 5 + for utext in textwrap.wrap(upper_text, 25): + upper_width = draw.textlength(utext, font=font) + draw.text( + ((width - upper_width) / 2, curr_height), + unidecode(utext), + (255, 255, 255), + font, + stroke_width=3, + stroke_fill=fiill, + ) + curr_height += font_size + padding + + curr_height = height - font_size + for ltext in reversed(textwrap.wrap(lower_text, 25)): + lower_width = draw.textlength(ltext, font=font) + draw.text( + ((width - lower_width) / 2, curr_height - font_size), + ltext, + (255, 255, 255), + font, + stroke_width=3, + stroke_fill=fiill, + ) + curr_height -= font_size + padding if sticker: stick_path = image_path @@ -214,7 +338,7 @@ async def draw_meme(image_path: str, text: str, sticker: bool, fiill: str) -> li stick_path = await resize_file_to_sticker_size(image_path) image1 = image_path - image2 = tosticker(stick_path,"@memesofdank_memer_hu_vai.webp") + image2 = tosticker(stick_path, f"@GojoSuperbot_{int(time())}.webp") image.save(image1) image.save(image2) @@ -224,123 +348,15 @@ async def draw_meme(image_path: str, text: str, sticker: bool, fiill: str) -> li return [image1, image2] -# async def draw_meme(image_path, text:str,stick): -# """Hellbot se churaya hai hue hue hue...""" -# img = Image.open(image_path) -# i_width, i_height = img.size -# m_font = ImageFont.truetype( -# "./extras/comic.ttf", int(i_width / 11) -# ) -# if ";" in text: -# upper_text, lower_text = text.split(";") -# else: -# upper_text = text -# lower_text = "" -# draw = ImageDraw.Draw(img) -# current_h, pad = 10, 5 -# if upper_text: -# for u_text in textwrap.wrap(upper_text,width=15,subsequent_indent=" "): -# u_width, u_height = draw.textsize(u_text, font=m_font) -# draw.text( -# xy=(((i_width - u_width) / 2) - 1, int((current_h / 640) * i_width)), -# text=u_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=(((i_width - u_width) / 2) + 1, int((current_h / 640) * i_width)), -# text=u_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=((i_width - u_width) / 2, int(((current_h / 640) * i_width)) - 1), -# text=u_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=(((i_width - u_width) / 2), int(((current_h / 640) * i_width)) + 1), -# text=u_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=((i_width - u_width) / 2, int((current_h / 640) * i_width)), -# text=u_text, -# font=m_font, -# fill=(255, 255, 255), -# ) -# current_h += u_height + pad -# if lower_text: -# for l_text in textwrap.wrap(upper_text,width=15,subsequent_indent=" "): -# u_width, u_height = draw.textsize(l_text, font=m_font) -# draw.text( -# xy=( -# ((i_width - u_width) / 2) - 1, -# i_height - u_height - int((20 / 640) * i_width), -# ), -# text=l_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=( -# ((i_width - u_width) / 2) + 1, -# i_height - u_height - int((20 / 640) * i_width), -# ), -# text=l_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=( -# (i_width - u_width) / 2, -# (i_height - u_height - int((20 / 640) * i_width)) - 1, -# ), -# text=l_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=( -# (i_width - u_width) / 2, -# (i_height - u_height - int((20 / 640) * i_width)) + 1, -# ), -# text=l_text, -# font=m_font, -# fill=(0, 0, 0), -# ) -# draw.text( -# xy=( -# (i_width - u_width) / 2, -# i_height - u_height - int((20 / 640) * i_width), -# ), -# text=l_text, -# font=m_font, -# fill=(255, 255, 255), -# ) -# current_h += u_height + pad - -# hue = image_path -# if stick: -# stick_path = image_path -# else: -# stick_path = await resize_file_to_sticker_size(hue) -# mee = tosticker(stick_path,"@memesofdank_memer_hu_vai.webp") -# img.save(hue) -# img.save(mee) -# return hue, mee - def toimage(image, filename=None, is_direc=False): - filename = filename if filename else "gojo.jpg" + filename = filename if filename else "gojo.png" if is_direc: - os.rename(image,filename) + os.rename(image, filename) return filename img = Image.open(image) if img.mode != "RGB": img = img.convert("RGB") - img.save(filename, "jpeg") + img.save(filename, "png") os.remove(image) return filename @@ -348,11 +364,11 @@ def toimage(image, filename=None, is_direc=False): def tosticker(response, filename=None, is_direc=False): filename = filename if filename else "gojo.webp" if is_direc: - os.rename(response,filename) + os.rename(response, filename) return filename image = Image.open(response) if image.mode != "RGB": image.convert("RGB") image.save(filename, "webp") os.remove(response) - return filename \ No newline at end of file + return filename diff --git a/Powers/utils/string.py b/Powers/utils/string.py index 487f408a14257d93005e789ee001f59dea7ac53e..2051ff0e8fb674a0ea1aaaf176f0e4e56f3e31ac 100644 --- a/Powers/utils/string.py +++ b/Powers/utils/string.py @@ -1,3 +1,4 @@ +import base64 from datetime import datetime, timedelta from html import escape from re import compile as compile_re @@ -9,7 +10,8 @@ from pyrogram.types import InlineKeyboardButton, Message from Powers import TIME_ZONE from Powers.utils.parser import escape_markdown -BTN_URL_REGEX = compile_re(r"(\[([^\[]+?)\]\(buttonurl:(?:/{0,2})(.+?)(:same)?\))") +BTN_URL_REGEX = compile_re( + r"(\[([^\[]+?)\]\(buttonurl:(?:/{0,2})(.+?)(:same)?\))") async def extract_time(m: Message, time_val: str): @@ -26,7 +28,7 @@ async def extract_time(m: Message, time_val: str): elif unit == "h": bantime = initial_time + timedelta(hours=int(time_num)) elif unit == "d": - bantime = initial_time + timedelta(days=int(time_num)) + bantime = initial_time + timedelta(days=int(time_num)) else: # how even...? return "" @@ -54,8 +56,9 @@ async def parse_button(text: str): # if even, not escaped -> create button if n_escapes % 2 == 0: # create a thruple with button label, url, and newline status - buttons.append((match.group(2), match.group(3), bool(match.group(4)))) - note_data += markdown_note[prev : match.start(1)] + buttons.append( + (match.group(2), match.group(3), bool(match.group(4)))) + note_data += markdown_note[prev: match.start(1)] prev = match.end(1) # if odd, escaped -> move along else: @@ -98,7 +101,7 @@ async def escape_invalid_curly_brackets(text: str, valids: List[str]) -> str: success = True break if success: - new_text += text[idx : idx + len(v) + 2] + new_text += text[idx: idx + len(v) + 2] idx += len(v) + 2 continue new_text += "{{" @@ -173,7 +176,7 @@ async def split_quotes(text: str): # 1 to avoid starting quote, and counter is exclusive so avoids ending key = await remove_escapes(text[1:counter].strip()) # index will be in range, or `else` would have been executed and returned - rest = text[counter + 1 :].strip() + rest = text[counter + 1:].strip() if not key: key = text[0] + text[0] return list(filter(None, [key, rest])) @@ -192,3 +195,25 @@ async def remove_escapes(text: str) -> str: else: res += text[counter] return res + + +async def encode_decode(string: str, to_do="encode"): + """ + Function to encode or decode strings + string: string to be decoded or encoded + to_do: encode to encode the string or decode to decode the string + """ + if to_do.lower() == "encode": + encodee = string.encode("ascii") + base64_ = base64.b64encode(encodee) + B64 = base64_.decode("ascii") + + elif to_do.lower() == "decode": + decodee = string.encode("ascii") + base64_ = base64.b64decode(decodee) + B64 = base64_.decode("ascii") + + else: + B64 = None + + return B64 diff --git a/Powers/utils/web_helpers.py b/Powers/utils/web_helpers.py index a27572b4fe3784ec5fd1adf0e98a8bfc8b297b1a..18359ec47d3b0276c410bcfbb9c8fc6c85fbf986 100644 --- a/Powers/utils/web_helpers.py +++ b/Powers/utils/web_helpers.py @@ -1,21 +1,88 @@ -import json +import math import os +import time from traceback import format_exc -from urllib import parse from pyrogram.types import InlineKeyboardButton as IKB from pyrogram.types import InlineKeyboardMarkup as IKM from pyrogram.types import Message -# import yt_dlp -from pytube import YouTube -from youtubesearchpython.__future__ import Video, VideosSearch +from pytube import YouTube, extract +from youtubesearchpython.__future__ import VideosSearch +from yt_dlp import YoutubeDL -from Powers.bot_class import LOGGER, MESSAGE_DUMP, Gojo +from Powers import youtube_dir +from Powers.bot_class import LOGGER, Gojo from Powers.utils.http_helper import * from Powers.utils.sticker_help import resize_file_to_sticker_size +from Powers.utils.web_scrapper import SCRAP_DATA backUP = "https://artfiles.alphacoders.com/160/160160.jpeg" +def readable_time(seconds: int) -> str: + count = 0 + out_time = "" + time_list = [] + time_suffix_list = ["secs", "mins", "hrs", "days"] + + while count < 4: + count += 1 + remainder, result = divmod(seconds, 60) if count < 3 else divmod(seconds, 24) + if seconds == 0 and remainder == 0: + break + time_list.append(int(result)) + seconds = int(remainder) + + for x in range(len(time_list)): + time_list[x] = str(time_list[x]) + time_suffix_list[x] + + if len(time_list) == 4: + out_time += time_list.pop() + ", " + + time_list.reverse() + out_time += " ".join(time_list) + + return out_time or "0 secs" + + +def humanbytes(size: int): + if not size: + return "" + power = 2**10 + number = 0 + dict_power_n = {0: " ", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"} + while size > power: + size /= power + number += 1 + return str(round(size, 2)) + " " + dict_power_n[number] + "B" + +async def progress( + current: int, total: int, message: Message, start: float, process: str +): + now = time.time() + diff = now - start + if round(diff % 10.00) == 0 or current == total: + percentage = current * 100 / total + speed = current / diff + elapsed_time = round(diff) * 1000 + complete_time = round((total - current) / speed) * 1000 + estimated_total_time = elapsed_time + complete_time + progress_str = "**[{0}{1}] : {2}%\n**".format( + "".join(["โ—" for i in range(math.floor(percentage / 10))]), + "".join(["โ—‹" for i in range(10 - math.floor(percentage / 10))]), + round(percentage, 2), + ) + msg = ( + progress_str + + "__{0}__ **๐—ˆ๐–ฟ** __{1}__\n**๐–ฒ๐—‰๐–พ๐–พ๐–ฝ:** __{2}/s__\n**๐–ค๐–ณ๐– :** __{3}__".format( + humanbytes(current), + humanbytes(total), + humanbytes(speed), + readable_time(estimated_total_time / 1000), + ) + ) + await message.edit_text(f"**{process} ...**\n\n{msg}") + + async def get_file_size(file: Message): if file.photo: size = file.photo.file_size/1024 @@ -33,7 +100,7 @@ async def get_file_size(file: Message): size = file.voice.file_size/1024 elif file.video_note: size = file.video_note.file_size/1024 - + if size <= 1024: return f"{round(size)} kb" elif size > 1024: @@ -44,6 +111,15 @@ async def get_file_size(file: Message): size = size/1024 return f"{round(size)} gb" +def get_video_id(url): + try: + _id = extract.video_id(url) + if not _id: + return None + else: + return _id + except: + return None def get_duration_in_sec(dur: str): duration = dur.split(":") @@ -54,15 +130,12 @@ def get_duration_in_sec(dur: str): return dur # Gets yt result of given query. -async def song_search(query, is_direct, max_results=1): + + +async def song_search(query, max_results=1): yt_dict = {} try: - if is_direct: - vid = Video.getInfo(query) - query = vid["title"] - else: - query = query - videos = VideosSearch(query,max_results) + videos = VideosSearch(query, max_results) results = await videos.next() except Exception as e: LOGGER.error(e) @@ -87,10 +160,13 @@ async def song_search(query, is_direct, max_results=1): "duration": i["accessibility"]['duration'], "DURATION": i["duration"], "published": i["publishedTime"], - "uploader": i ["channel"]["name"] - } + } try: - thumb = {"thumbnail": i["richThumbnail"]["url"]} + dict_form["uploader"] = i["channel"]["name"] + except: + dict_form["uploader"] = "Captain D. Ezio" + try: + thumb = {"thumbnail": i["thumbnails"][0]["url"]} except Exception: thumb = {"thumbnail": None} dict_form.update(thumb) @@ -100,11 +176,10 @@ async def song_search(query, is_direct, max_results=1): pass return yt_dict -"""song_opts = { +song_opts = { "format": "bestaudio", "addmetadata": True, "key": "FFmpegMetadata", - "writethumbnail": True, "prefer_ffmpeg": True, "geo_bypass": True, "nocheckcertificate": True, @@ -115,43 +190,42 @@ async def song_search(query, is_direct, max_results=1): "preferredquality": "480", } ], - "outtmpl": "%(id)s.mp3", + "outtmpl": "%(id)s", "quiet": True, "logtostderr": False, } - video_opts = { - "format": "best", - "addmetadata": True, - "key": "FFmpegMetadata", - "prefer_ffmpeg": True, - "geo_bypass": True, - "nocheckcertificate": True, - "postprocessors": [ - { - "key": "FFmpegVideoConvertor", - "preferedformat": "mp4", - } - ], - "outtmpl": "%(id)s.mp4", - "logtostderr": False, - "quiet": True, -}""" - - + "format": "best", + "addmetadata": True, + "key": "FFmpegMetadata", + "prefer_ffmpeg": True, + "geo_bypass": True, + "nocheckcertificate": True, + "postprocessors": [ + { + "key": "FFmpegVideoConvertor", + "preferedformat": "mp4", + } + ], + "outtmpl": "%(id)s.mp4", + "quiet": True, + "logtostderr": False, + } -async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str): +async def youtube_downloader(c: Gojo, m: Message, query: str, type_: str): if type_ == "a": - # opts = song_opts + opts = song_opts video = False song = True + ext = "mp3" elif type_ == "v": - # opts = video_opts + opts = video_opts video = True song = False + ext = "mp4" # ydl = yt_dlp.YoutubeDL(opts) - dicti = await song_search(query, is_direct,1) + dicti = await song_search(query, 1) if not dicti and type(dicti) != str: await m.reply_text("File with duration less than or equals to 10 minutes is allowed only") elif type(dicti) == str: @@ -162,6 +236,9 @@ async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str except KeyError: return yt = YouTube(query) + if yt.age_restricted: + await m.reply_text("This video is age restricted") + return dicti = dicti[1] f_name = dicti["title"] views = dicti["views"] @@ -172,15 +249,22 @@ async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str vid_dur = get_duration_in_sec(dicti["DURATION"]) published_on = dicti["published"] if thumb: - thumb_ = await c.send_photo(MESSAGE_DUMP,thumb) + try: + thumb = SCRAP_DATA(thumb).get_images() + thumb = await resize_file_to_sticker_size(thumb[0], 320, 320) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + LOGGER.info("Using back up image as thumbnail") + thumb = SCRAP_DATA(backUP).get_images() + thumb = await resize_file_to_sticker_size(thumb[0], 320, 320) + else: - thumb_ = await c.send_photo(MESSAGE_DUMP,backUP) + thumb = SCRAP_DATA(backUP).get_images() + thumb = await resize_file_to_sticker_size(thumb[0], 320, 320) + # FILE = ydl.extract_info(query,download=video) url = query - thumb = await thumb_.download() - if not thumb: - thumb = await resize_file_to_sticker_size(thumb,320,320) - await thumb_.delete() cap = f""" โคท Name: `{f_name}` โคท Duration: `{dura}` @@ -189,32 +273,52 @@ async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str Downloaded by: @{c.me.username} """ + upload_text = f"**โฌ†๏ธ ๐–ด๐—‰๐—…๐—ˆ๐–บ๐–ฝ๐—‚๐—‡๐—€ {'audio' if song else 'video'}** \\**โš˜ ๐–ณ๐—‚๐—๐—…๐–พ:** `{f_name[:50]}`\n*โš˜ ๐–ข๐—๐–บ๐—‡๐—‡๐–พ๐—…:** `{uploader}`" kb = IKM( [ [ - IKB(f"โœ˜ {uploader.capitalize()} โœ˜",url=f"{up_url}") + IKB(f"โœ˜ {uploader.capitalize()} โœ˜", url=f"{up_url}") ], [ IKB(f"โœ˜ Youtube url โœ˜", url=f"{url}") ] ] ) + + def get_my_file(opts, ext): + try: + with YoutubeDL(opts) as ydl: + ydl.download([query]) + info = ydl.extract_info(query, False) + file_name = ydl.prepare_filename(info) + if len(file_name.rsplit(".", 1)) == 2: + pass + else: + file_name = f"{file_name}.{ext}" + new = info['title'].replace('/','|').replace('\\','|') + new_file = f"{youtube_dir}{new}.{ext}" + os.rename(file_name, new_file) + return True, new_file + except Exception as e: + return False, str(e) + if song: - audio_stream= yt.streams.filter(only_audio=True).first() - f_path = audio_stream.download() - # file_path = f"./youtube_downloads/{f_name.strip()}.mp3" - file_path = f"./{f_name.strip()}.mp3" - os.rename(f_path,file_path) - await m.reply_audio(file_path,caption=cap,reply_markup=kb,duration=vid_dur,thumb=thumb,title=f_name) - # os.remove(f_path) + success, file_path = get_my_file(opts, ext) + if not success: + await m.reply_text(file_path) + return + msg = await m.reply_text(upload_text) + await m.reply_audio(file_path, caption=cap, reply_markup=kb, duration=vid_dur, thumb=thumb, title=f_name,performer=uploader, progress=progress, progress_args=(msg, time.time(), upload_text)) + await msg.delete() os.remove(file_path) - os.remove(thumb) return elif video: - video_stream = yt.streams.get_highest_resolution() - file_path = video_stream.download() - # file_path = f"./youtube_downloads/{f_name}.mp4" - await m.reply_video(file_path,caption=cap,reply_markup=kb,duration=vid_dur,thumb=thumb) + success, file_path = get_my_file(opts, ext) + if not success: + await m.reply_text(file_path) + return + msg = await m.reply_text(upload_text) + await m.reply_video(file_path, caption=cap, reply_markup=kb, duration=vid_dur, thumb=thumb, progress=progress, progress_args=(msg, time.time(), upload_text)) + await msg.delete() os.remove(file_path) - os.remove(thumb) return diff --git a/Powers/utils/web_scrapper.py b/Powers/utils/web_scrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..8eef1cdebfc7a68277c19ca703769de7a9ea7e9e --- /dev/null +++ b/Powers/utils/web_scrapper.py @@ -0,0 +1,229 @@ +import os +import re +from typing import List + +import httpx + +from Powers import * + +# import requests +# from selenium import webdriver +# from selenium.webdriver.chrome.options import Options +# from selenium.webdriver.chrome.service import Service +# from selenium.webdriver.common.by import By +# from selenium.webdriver.support.expected_conditions import \ +# presence_of_element_located +# from selenium.webdriver.support.wait import WebDriverWait + + + +class SCRAP_DATA: + """Class to get and handel scrapped data""" + + def __init__(self, urls: List[str] or str) -> None: + self.urls = urls + self.path = scrap_dir + if not os.path.isdir(self.path): + os.makedirs(self.path) + + def get_images(self) -> list: + images = [] + if isinstance(self.urls, str): + requested = httpx.get(self.urls) + try: + name = self.path + f"img_{str(time()).replace('.','_')}.jpg" + with open(name, "wb") as f: + f.write(requested.content) + images.append(name) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + requested.close() + else: + for i in self.urls: + if i: + requested = httpx.get(i) + else: + continue + try: + name = self.path + f"img_{str(time()).replace('.','_')}.jpg" + with open(name, "wb") as f: + f.write(requested.content) + images.append(name) + except Exception as e: + LOGGER.error(format_exc()) + LOGGER.error(e) + requested.close() + continue + return images + + def get_videos(self) -> list: + videos = [] + if isinstance(self.urls, str): + if i: + requested = httpx.get(i) + else: + return [] + try: + name = self.path + f"vid_{str(time()).replace('.','_')}.mp4" + with open(name, "wb") as f: + f.write(requested.content) + videos.append(name) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + requested.close() + else: + for i in self.urls: + if i: + requested = httpx.get(i) + else: + continue + try: + name = self.path + f"vid_{str(time()).replace('.','_')}.mp4" + with open(name, "wb") as f: + f.write(requested.content) + videos.append(name) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + requested.close() + continue + return videos + + +# class DRIVER: +# """Class to make selenium driver""" + +# def __init__(self) -> None: +# self.BIN = CHROME_BIN +# self.CHROME_DRIVER = CHROME_DRIVER + +# def initialize_driver(self): +# if not self.BIN: +# LOGGER.error( +# "ChromeBinaryErr: No binary path found! Install Chromium or Google Chrome.") +# return ( +# None, +# "ChromeBinaryErr: No binary path found! Install Chromium or Google Chrome.", +# ) + +# try: +# options = Options() +# options.binary_location = self.BIN +# options.add_argument("--disable-dev-shm-usage") +# options.add_argument("--ignore-certificate-errors") +# options.add_argument("--disable-gpu") +# options.add_argument("--headless=new") +# options.add_argument("--test-type") +# options.add_argument("--no-sandbox") + +# service = Service(self.CHROME_DRIVER) +# driver = webdriver.Chrome(options, service) +# return driver, None +# except Exception as e: +# LOGGER.error(f"ChromeDriverErr: {e}") +# return None, f"ChromeDriverErr: {e}" + +# def driver_close(self, driver: webdriver.Chrome): +# driver.close() +# driver.quit() + + +# class INSTAGRAM(DRIVER): +# """Class to scrap data from instagram""" + +# def __init__(self, url: str) -> None: +# self.url = url +# self.article = "article._aa6a" +# self.ul_class = "_acay" +# self.image_class = "x5yr21d" +# self.video_class = "x1lliihq" +# self.next_button = "button._afxw" +# self.return_dict = {"image": [], "video": []} +# super().__init__() + +# def is_correct_link(self): +# return bool((re.compile(r"^https?://(?:www\.)?instagram\.com/")).match(self.url)) + +# def get_all(self): +# driver, error = self.initialize_driver() +# if not driver: +# return error + +# driver.get(self.url) +# wait = WebDriverWait(driver, 30) +# if "reel" in self.url: +# element = wait.until( +# presence_of_element_located((By.TAG_NAME, "video"))) +# reels = element.get_attribute("src") +# self.driver_close(driver) +# self.return_dict.get("video").append(reels) +# return self.return_dict +# elif bool((re.compile(r"^https?://(?:www\.)?instagram\.com/p/")).match(self.url)): +# image_links = [] +# video_links = [] +# try: +# element = wait.until(presence_of_element_located( +# (By.CLASS_NAME, self.ul_class))) + +# while True: +# sub_element = element.find_elements( +# By.CLASS_NAME, self.image_class) +# for i in sub_element: +# url = i.get_attribute("src") +# image_links.append(url) + +# sub_element = element.find_elements( +# By.CLASS_NAME, self.video_class) +# for i in sub_element: +# url = i.get_attribute("src") +# video_links.append(url) + +# try: +# driver.find_element( +# By.CSS_SELECTOR, self.next_button).click() +# except: # Failed to either find the element or click on next i.e. no more media left in post +# break +# except: +# element = wait.until(presence_of_element_located( +# (By.CSS_SELECTOR, self.article))) +# try: +# sub_element = element.find_element(By.TAG_NAME, "img") +# image_links.append(sub_element.get_attribute("src")) +# except: +# sub_element = element.find_element(By.TAG_NAME, "video") +# video_links.append(sub_element.get_attribute("src")) + +# self.driver_close(driver) +# # To remove duplicates here I am converting into set +# if image_links: +# image_links = list(set(image_links)) +# if video_links: +# video_links = list(set(video_links)) +# for i in video_links: +# image_links.remove(i) + +# self.return_dict.get("image").extend(image_links) +# self.return_dict.get("video").extend(video_links) +# return self.return_dict + +# else: +# return {} + + +class INSTAGRAM: + def __init__(self, url): + self.url = url + + def is_correct_url(self): + return bool((re.compile(r"^https?://(?:www\.)?instagram\.com/")).match(self.url)) + + def get_media(self): + try: + response = httpx.post(f"https://api.qewertyy.dev/downloaders/instagram?url={self.url}").json() + return response + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + return {"code": 69, "message": e} \ No newline at end of file diff --git a/Powers/vars.py b/Powers/vars.py index d934048c583fe02ac7d56bb7e1bb9b8948a7542f..23562d3d6105b62a9a6d419a9942f67f1b625dd2 100644 --- a/Powers/vars.py +++ b/Powers/vars.py @@ -1,11 +1,11 @@ -from os import getcwd +from os import getcwd, path from prettyconf import Configuration from prettyconf.loaders import EnvFile, Environment env_file = f"{getcwd()}/.env" config = Configuration(loaders=[Environment(), EnvFile(filename=env_file)]) - +is_env = path.isfile(env_file) class Config: """Config class for variables.""" @@ -15,7 +15,7 @@ class Config: API_ID = int(config("API_ID", default="123")) API_HASH = config("API_HASH", default=None) OWNER_ID = int(config("OWNER_ID", default=1344569458)) - MESSAGE_DUMP = int(config("MESSAGE_DUMP")) + MESSAGE_DUMP = int(config("MESSAGE_DUMP", default = "0")) # if not given owner id will be msg dump :) DEV_USERS = [ int(i) for i in config( @@ -34,25 +34,26 @@ class Config: int(i) for i in config( "WHITELIST_USERS", - default="", + default="" ).split(None) ] - GENIUS_API_TOKEN = config("GENIUS_API",default=None) - AuDD_API = config("AuDD_API",default=None) - RMBG_API = config("RMBG_API",default=None) - DB_URI = config("DB_URI", default="") + # CHROME_BIN = config("CHROME_BIN", "/app/.apt/usr/bin/google-chrome") + # CHROME_DRIVER = config("CHROME_DRIVER", default="/app/.chromedriver/bin/chromedriver") + GENIUS_API_TOKEN = config("GENIUS_API", default=None) + # AuDD_API = config("AuDD_API",default=None) + RMBG_API = config("RMBG_API", default=None) + DB_URI = config("DB_URI", default=None) DB_NAME = config("DB_NAME", default="gojo_satarou") - BDB_URI = config("BDB_URI",default=None) + BDB_URI = config("BDB_URI", default=None) NO_LOAD = config("NO_LOAD", default="").split() PREFIX_HANDLER = config("PREFIX_HANDLER", default="/").split() SUPPORT_GROUP = config("SUPPORT_GROUP", default="gojo_bots_network") SUPPORT_CHANNEL = config("SUPPORT_CHANNEL", default="gojo_bots_network") WORKERS = int(config("WORKERS", default=16)) - TIME_ZONE = config("TIME_ZONE",default='Asia/Kolkata') - BOT_USERNAME = "" - BOT_ID = "" - BOT_NAME = "" - owner_username = "" + TIME_ZONE = config("TIME_ZONE", default='Asia/Kolkata') + BOT_USERNAME = "" # Leave it as it is + BOT_ID = "" # Leave it as it is + BOT_NAME = "" # Leave it as it is class Development: @@ -64,7 +65,7 @@ class Development: API_ID = 12345 # Your APP_ID from Telegram API_HASH = "YOUR API HASH" # Your APP_HASH from Telegram OWNER_ID = 1344569458 # Your telegram user id defult to mine - MESSAGE_DUMP = -100845454887 # Your Private Group ID for logs + MESSAGE_DUMP = 0 # Your Private Group ID for logs if not passed your owner id will be msg dump DEV_USERS = [] SUDO_USERS = [] WHITELIST_USERS = [] @@ -73,10 +74,12 @@ class Development: NO_LOAD = [] GENIUS_API_TOKEN = "" RMBG_API = "" - PREFIX_HANDLER = ["!", "/","$"] + PREFIX_HANDLER = ["!", "/", "$"] SUPPORT_GROUP = "SUPPORT_GROUP" SUPPORT_CHANNEL = "SUPPORT_CHANNEL" VERSION = "VERSION" TIME_ZONE = 'Asia/Kolkata' BDB_URI = "" WORKERS = 8 + # CHROME_BIN = "/app/.apt/usr/bin/google-chrome" + # CHROME_DRIVER = "/app/.chromedriver/bin/chromedriver" diff --git a/README.md b/README.md index c56179624c508aa49a9bb118f231e89eef4538d3..978450087ff88f57655743e7eb1c98a26662dc40 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Not a particular inspiration, inspired by many bots Mainly: * [Alita_Robot](https://github.com/divideprojects/Alita_Robot) - +* [WilliamButcherBot](https://github.com/TheHamkerCat/WilliamButcherBot) --------- @@ -173,7 +173,7 @@ If all works well, the bot should send a message to the MESSAGE_DUMP Group!---> `DB_URI` Your [MongoDB](https://www.mongodb.com/) connection string. -`MESSAGE_DUMP`: Event logs channel where the bot will send updates. Note that it should start with `-100`. +`MESSAGE_DUMP`: Event logs channel where the bot will send updates. Note that it should start with `-100`. If you don't give it or pass 0 in it your owner id will be the message dump for the bot. @@ -213,6 +213,10 @@ If all works well, the bot should send a message to the MESSAGE_DUMP Group!---> `WHITELIST_USERS`: A space-separated list of user IDs whitelisted, cannot be restricted. +`CHROME_BIN`: Location of your chrome bin. + +`CHROME_DRIVER`: Location of your chrome driver. + โš ๏ธ **Note:** In case you are passing more than one value separate them using whitespace (space) for example If I want to pass more than one PREFIX_HANDLER I'll pass it like `'/' '.' '!'` this. @@ -285,6 +289,8 @@ Some special thanks to the person/repo who/which helped and motivated me to crea * [Alita_Robot](https://github.com/divideprojects/Alita_Robot) for base code. +* [WilliamButcherBot](https://github.com/TheHamkerCat/WilliamButcherBot) for few plugins inspirations. + --------- # Powered by [ษขึ…สึ… ษฎึ…ศถึ†](https://github.com/Gojo-Bots) diff --git a/Version/version 2.2.0.md b/Version/version 2.2.0.md new file mode 100644 index 0000000000000000000000000000000000000000..3a8a1e953ecb7a038328797a5156514ba5cff9e5 --- /dev/null +++ b/Version/version 2.2.0.md @@ -0,0 +1,33 @@ +# V 2.2.0 + +## Changes made + +- Added AFK support. +- Added captcha support. +- Added cache for support users and few other to prevent script from requesting data from database frequently. +- Added instagram support. Now you can download any public post and reel. +- Added new lock type: `bot`. +- Added pagination for long caption in help menu. +- Added quote feature. Now you can quote any message. +- Added support for join request. + +- Changed sticker packname so new kanged sticker will not be added in your previous packs. Number of stickers in a pack is increased to 120 for all sticker pack type. + +- Fixed error while kanging stickers. +- Fixed few bugs in greeting the users. +- Improved few things in locks. +- Fixed user getting banned instead of kick when they flood. +- Fixed `400: Bad Request` error while downloading audio or video from youtube. + +- Merged all pull requests. + +- Fixed few bugs. (I don't know exactly what bugs and I forgot any more changes I made :)) +- Created few bugs. (unintentional) + +## Report issues [here](https://github.com/Gojo-Bots/Gojo_Satoru/issues/new/choose) if find any + +## Give ideas [here](https://github.com/Gojo-Bots/Gojo_Satoru/discussions/new?category=ideas) for next update + +## Trying our best to give the best + +## Regards ๐Ÿง‘โ€๐Ÿ’ป: [Captain D. Ezio](https://github.com/iamgojoof6eyes) diff --git a/app.json b/app.json index 1703fa8e323cf5b5a3e171a0a437cc6f27d1b140..ea47694129cbe4b8b8f8b4ad4bd00a83fdcf3a9a 100644 --- a/app.json +++ b/app.json @@ -114,6 +114,15 @@ { "url":"https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest" }, + { + "url": "https://github.com/chrismytton/heroku-buildpack-jq" + }, + { + "url":"https://github.com/heroku/heroku-buildpack-google-chrome" + }, + { + "url":"https://github.com/heroku/heroku-buildpack-chromedriver" + }, { "url": "heroku/python" } diff --git a/requirements.txt b/requirements.txt index 52df6f504310b66747653cbaa8105bec626c0c01..955cd9b550c274311ade5451a3f3b26d3d57529d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,41 +1,42 @@ -aiofiles==23.2.1; python_full_version >= "3.7" -anyio==4.2.0; python_full_version >= "3.6.2" and python_version >= "3.6" +aiofiles==23.2.1 apscheduler==3.10.4 asyncio==3.4.3 -beautifulsoup4==4.12.2; python_full_version >= "3.6" -cachetools==5.2.0; python_version >= "3.7" and python_version < "4.0" +beautifulsoup4==4.12.2 +cachetools==5.2.0 captcha==0.5.0 -certifi==2023.7.22; python_version >= "3.7" and python_version < "4" -charset-normalizer==2.1.0; python_version >= "3.7" and python_version < "4" and python_full_version >= "3.6.0" -dnspython==2.2.1; python_version >= "3.6" and python_version < "4.0" +certifi==2023.7.22 +charset-normalizer==2.1.0 +dnspython==2.2.1 google==3.0.0 -gpytranslate==1.5.1; python_version >= "3.6" +gpytranslate==1.5.1 +httpx lyricsgenius==3.0.1 -lxml==4.9.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" pillow == 10.3.0 +lxml==4.9.1 +pillow == 10.1.0 prettyconf==2.2.1 -pyaes==1.6.1; python_version >= "3.6" and python_version < "4.0" +pyaes==1.6.1 pymongo==4.6.1 -pyrogram==2.0.106; python_version >= "3.8" -pysocks==1.7.1; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" -python-dateutil==2.8.2; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") +git+https://github.com/KurimuzonAkuma/pyrogram.git@v2.1.32 +pysocks==1.7.1 +python-dateutil==2.8.2 pytube==15.0.0 pytz==2023.3 -pyyaml==6.0.1; python_version >= "3.6" +pyyaml==6.0.1 qrcode==7.4.2 -regex==2023.12.25; python_version >= "3.6" +regex==2023.12.25 requests==2.31.0 -rfc3986==1.5.0; python_version >= "3.7" +rfc3986==1.5.0 search-engine-parser==0.6.8 -six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" -sniffio==1.3.0; python_full_version >= "3.6.2" and python_version >= "3.7" -soupsieve==2.4; python_version >= "3.6" and python_full_version >= "3.6.0" -tgcrypto==1.2.5; python_version >= "3.6" and python_version < "4.0" +six==1.16.0 +sniffio==1.3.0 +soupsieve==2.4 +tgcrypto==1.2.5 tswift==0.7.0 -typing-extensions==4.5.0; python_full_version >= "3.6.2" and python_version >= "3.7" and python_version < "3.8" -ujson==5.8.0; python_version >= "3.7" -urllib3==1.26.18; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" +typing-extensions +ujson==5.8.0 +Unidecode uvloop==0.19.0 wikipedia==1.4.0 youtube-search-python==1.6.6 -yt-dlp@git+https://github.com/HellBoy-OP/yt-dp-fork.git@af1fd12f675220df6793fc019dff320bc76e8080 +yt-dlp@git+https://github.com/HellBoy-OP/yt-dp-fork.git@af1fd12f675220df6793fc019dff320bc76e8080 \ No newline at end of file