diff --git a/Powers/__init__.py b/Powers/__init__.py index 7a31c64a..04196bf2 100644 --- a/Powers/__init__.py +++ b/Powers/__init__.py @@ -77,7 +77,6 @@ LOGGER.info(f"Time zone set to {Config.TIME_ZONE}") LOGGER.info("Source Code: https://github.com/Gojo-Bots/Gojo_Satoru\n") LOGGER.info("Checking lyrics genius api...") -LOGGER.info("Initialising telegraph client") # API based clients if Config.GENIUS_API_TOKEN: @@ -127,14 +126,14 @@ WHITELIST_USERS = Config.WHITELIST_USERS -defult_dev = [1344569458, 5301411431, 1432756163, 1854700253, 1174290051, 1218475925, 960958169, 5294360309] + +defult_dev = [1344569458, 1432756163, 5294360309] + [int(OWNER_ID)] + Defult_dev = set(defult_dev) DEVS = DEVS_USER | Defult_dev DEV_USERS = list(DEVS) -SUPPORT_STAFF = list( - set([int(OWNER_ID)] + SUDO_USERS + DEV + WHITELIST_USERS + DEV_USERS), -) # Remove duplicates by using a set + # Plugins, DB and Workers DB_URI = Config.DB_URI DB_NAME = Config.DB_NAME @@ -143,10 +142,14 @@ BDB_URI = Config.BDB_URI # Prefixes +PREFIX_HANDLER = Config.PREFIX_HANDLER HELP_COMMANDS = {} # For help menu UPTIME = time() # Check bot uptime +from apscheduler.schedulers.asyncio import AsyncIOScheduler + +scheduler = AsyncIOScheduler(timezone=TIME_ZONE) async def load_cmds(all_plugins): """Loads all the plugins in bot.""" diff --git a/Powers/__main__.py b/Powers/__main__.py index 4da8c4b5..29bef2b4 100644 --- a/Powers/__main__.py +++ b/Powers/__main__.py @@ -1,17 +1,8 @@ -import uvloop # Comment it out if using on windows -from apscheduler.schedulers.asyncio import AsyncIOScheduler - -from Powers import BDB_URI, TIME_ZONE +# import uvloop # Comment it out if using on windows from Powers.bot_class import Gojo -from Powers.plugins.birthday import send_wishish -from Powers.plugins.clean_db import clean_my_db - -scheduler = AsyncIOScheduler(timezone=TIME_ZONE) if __name__ == "__main__": - uvloop.install() # Comment it out if using on windows + # uvloop.install() # Comment it out if using on windows Gojo().run() - scheduler.add_job(clean_my_db,'cron',[Gojo()],hour=3,minute=0,second=0) - if BDB_URI: - scheduler.add_job(send_wishish,'cron',[Gojo()],hour=0,minute=0,second=0) - scheduler.start() + + diff --git a/Powers/bot_class.py b/Powers/bot_class.py index ffee6436..42c5effc 100644 --- a/Powers/bot_class.py +++ b/Powers/bot_class.py @@ -6,11 +6,13 @@ from pyrogram.raw.all import layer from pyrogram.types import BotCommand -from Powers import (API_HASH, API_ID, BOT_TOKEN, LOG_DATETIME, LOGFILE, LOGGER, - MESSAGE_DUMP, NO_LOAD, OWNER_ID, UPTIME, WORKERS, - load_cmds) +from Powers import (API_HASH, API_ID, BDB_URI, BOT_TOKEN, LOG_DATETIME, + LOGFILE, LOGGER, MESSAGE_DUMP, NO_LOAD, OWNER_ID, UPTIME, + WORKERS, load_cmds, scheduler) from Powers.database import MongoDB from Powers.plugins import all_plugins +from Powers.plugins.scheduled_jobs import * +from Powers.supports import * from Powers.vars import Config INITIAL_LOCK = RLock() @@ -51,12 +53,9 @@ async def start(self): ) meh = await self.get_me() # Get bot info from pyrogram client LOGGER.info("Starting bot...") - owner_user = (await self.get_users(OWNER_ID)).username - Config.owner_username = owner_user Config.BOT_ID = meh.id Config.BOT_NAME = meh.first_name Config.BOT_USERNAME = meh.username - startmsg = await self.send_message(MESSAGE_DUMP, "Starting Bot...") # Show in Log that bot has started @@ -67,9 +66,12 @@ async def start(self): # Get cmds and keys cmd_list = await load_cmds(await all_plugins()) - + await load_support_users() 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.start() # Send a message to MESSAGE_DUMP telling that the # bot has started and has loaded all plugins! await startmsg.edit_text( @@ -95,6 +97,7 @@ async def stop(self): "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( diff --git a/Powers/database/afk_db.py b/Powers/database/afk_db.py new file mode 100644 index 00000000..a91a5eb7 --- /dev/null +++ b/Powers/database/afk_db.py @@ -0,0 +1,55 @@ +from threading import RLock + +from Powers import LOGGER +from Powers.database import MongoDB + +INSERTION_LOCK = RLock() + + +class AFK(MongoDB): + """Class to store afk users""" + db_name = "afk" + + def __init__(self) -> None: + super().__init__(self.db_name) + + 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}) + if media: + 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 + } + ) + return True + + def check_afk(self, chat_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}) + if curr: + return curr + return + + def delete_afk(self, chat_id, user_id): + with INSERTION_LOCK: + 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 diff --git a/Powers/database/approve_db.py b/Powers/database/approve_db.py index 3cef38a3..8ba0b3ba 100644 --- a/Powers/database/approve_db.py +++ b/Powers/database/approve_db.py @@ -1,6 +1,8 @@ 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.""" diff --git a/Powers/database/autojoin_db.py b/Powers/database/autojoin_db.py new file mode 100644 index 00000000..3328e1f5 --- /dev/null +++ b/Powers/database/autojoin_db.py @@ -0,0 +1,50 @@ +from threading import RLock +from time import time + +from Powers import LOGGER +from Powers.database import MongoDB + +INSERTION_LOCK = RLock() + + +class AUTOJOIN(MongoDB): + """class to store auto join requests""" + + db_name = "autojoin" + + def __init__(self) -> None: + super().__init__(self.db_name) + + 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,}) + if not curr: + with INSERTION_LOCK: + self.insert_one({"chat_id":chat,"type":mode}) + return True + return False + + 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}) + if curr: + self.update({"chat_id":chat},{"type":mode}) + return + else: + return + + 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 diff --git a/Powers/database/captcha_db.py b/Powers/database/captcha_db.py new file mode 100644 index 00000000..8c55563c --- /dev/null +++ b/Powers/database/captcha_db.py @@ -0,0 +1,113 @@ +from threading import RLock + +from Powers import LOGGER +from Powers.database import MongoDB + +INSERTION_LOCK = RLock() + + +class CAPTCHA(MongoDB): + """Class to store captcha's info""" + db_name = "captcha" + + def __init__(self) -> None: + super().__init__(self.db_name) + + 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 + } + ) + return + + def is_captcha(self, chat): + curr = self.find_one({"chat_id": chat}) + if curr: + return True + return False + + def update_type(self, chat, captcha_type): + with INSERTION_LOCK: + curr = self.is_captcha(chat) + if curr: + 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}) + return + + def remove_captcha(self, chat): + with INSERTION_LOCK: + curr = self.is_captcha(chat) + if curr: + self.delete_one({"chat_id":chat}) + return + + def get_captcha(self, 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" + + def __init__(self) -> None: + super().__init__(self.db_name) + + def load_cap_data(self, chat, user, data): + 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}) + return True + else: + return + + def get_cap_data(self, chat, 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}) + if curr: + with INSERTION_LOCK: + 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}) + if not curr: + with INSERTION_LOCK: + 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}) + if curr: + return curr["message_id"] + else: + return False + + def del_message_id(self, chat, 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 diff --git a/Powers/database/locks_db.py b/Powers/database/locks_db.py new file mode 100644 index 00000000..c301e189 --- /dev/null +++ b/Powers/database/locks_db.py @@ -0,0 +1,84 @@ +from threading import RLock + +from Powers import LOGGER +from Powers.database import MongoDB + +INSERTION_LOCK = RLock() + +class LOCKS(MongoDB): + """Class to store locks""" + + db_name = "locks" + + def __init__(self) -> None: + super().__init__(self.db_name) + + def insert_lock_channel(self, chat: int, locktype: str): + """ + locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + """ + 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) + if not hmm: + 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 + """ + curr = self.find_one({"chat_id":chat,"locktype":locktype}) + if curr: + with INSERTION_LOCK: + self.delete_one({"chat_id":chat,"locktype":locktype}) + return True + else: + return False + + def get_lock_channel(self, locktype: str="all"): + """ + locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + """ + if locktype not in ["anti_c_send","anti_fwd","anti_fwd_u","anti_fwd_c","anti_links", "all"]: + return False + else: + if locktype == "all": + find = {} + else: + find = {"locktype":locktype} + curr = self.find_all(find) + if not curr: + list_ = [] + else: + list_ = [i["chat_id"] for i in curr] + return list_ + + 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"}) + elif locktype == "anti_fwd_c": + 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"}) + return True + else: + return False + + def is_particular_lock(self, chat: int, locktype: str): + """ + locktypes: anti_c_send, anti_fwd, anti_fwd_u, anti_fwd_c, anti_links + """ + 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/support_db.py b/Powers/database/support_db.py new file mode 100644 index 00000000..70f935c1 --- /dev/null +++ b/Powers/database/support_db.py @@ -0,0 +1,70 @@ +from threading import RLock + +from Powers import LOGGER +from Powers.database import MongoDB + +INSERTION_LOCK = RLock() + +class SUPPORTS(MongoDB): + """ + class to store support users in database + Dev > sudo > whitelist + """ + + db_name = "supports" + + def __init__(self) -> None: + super().__init__(self.db_name) + + def insert_support_user(self, user_id, support_type): + curr = self.is_support_user(user_id) + if not curr: + with INSERTION_LOCK: + self.insert_one( + { + "user_id":user_id, + "support_type":support_type + } + ) + return + + 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 + }, + { + "support_type":new_type + } + ) + return + + + def is_support_user(self, user_id): + curr = self.find_one({"user_id":user_id}) + if curr: + return True + return False + + def delete_support_user(self,user): + curr = self.is_support_user(user) + if curr: + with INSERTION_LOCK: + self.delete_one({"user_id":user}) + return + + 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}) + if curr: + return curr["support_type"] + return False \ No newline at end of file diff --git a/Powers/plugins/__init__.py b/Powers/plugins/__init__.py index 171c0ec3..cd4ed62e 100644 --- a/Powers/plugins/__init__.py +++ b/Powers/plugins/__init__.py @@ -30,3 +30,11 @@ async def all_plugins(): bday_info = Birth_main_db['users_bday'] bday_cinfo = Birth_main_db["chat_bday"] + +from datetime import datetime + + +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 41c31a97..1268a094 100644 --- a/Powers/plugins/admin.py +++ b/Powers/plugins/admin.py @@ -11,18 +11,21 @@ UserAdminInvalid) from pyrogram.types import ChatPrivileges, Message -from Powers import DEV_USERS, LOGGER, OWNER_ID, SUPPORT_GROUP, SUPPORT_STAFF +from Powers import LOGGER, OWNER_ID 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 (DEV_LEVEL, admin_filter, command, - owner_filter, promote_filter) +from Powers.utils.custom_filters import (admin_filter, command, owner_filter, + 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): @@ -580,6 +583,7 @@ async def setgpic(c: Gojo, m: Message): • /disabledel : Delete disabled commands when used by non-admins. • /disabled: List the disabled commands in this chat. • /enableall: enable all disabled commands. + **Example:** `/promote @username`: this promotes a user to admin.""" diff --git a/Powers/plugins/afk.py b/Powers/plugins/afk.py new file mode 100644 index 00000000..d6e0bb4f --- /dev/null +++ b/Powers/plugins/afk.py @@ -0,0 +1,167 @@ +from datetime import datetime +from random import choice + +from pyrogram import filters +from pyrogram.enums import ParseMode as PM +from pyrogram.types import Message + +from Powers import LOGGER, PREFIX_HANDLER +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 command +from Powers.utils.msg_types import Types, get_afk_type +from Powers.vars import Config + +# from traceback import format_exc + +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" +] + +@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(filters.group,group=-18) +async def afk_checker(c: Gojo, m: Message): + if not m.from_user: + return + + 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"]: + return + 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) + return + +__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 +""" + + + diff --git a/Powers/plugins/antispam.py b/Powers/plugins/antispam.py index 4d3a4229..1ca9ab81 100644 --- a/Powers/plugins/antispam.py +++ b/Powers/plugins/antispam.py @@ -5,11 +5,11 @@ from pyrogram.errors import MessageTooLong, PeerIdInvalid, UserIsBlocked from pyrogram.types import Message -from Powers import (LOGGER, MESSAGE_DUMP, SUPPORT_GROUP, SUPPORT_STAFF, - TIME_ZONE) +from Powers import LOGGER, MESSAGE_DUMP, SUPPORT_GROUP, TIME_ZONE 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 @@ -18,7 +18,7 @@ # Initialize db = GBan() - +SUPPORT_STAFF = get_support_staff() @Gojo.on_message(command(["gban", "globalban"], sudo_cmd=True)) async def gban(c: Gojo, m: Message): diff --git a/Powers/plugins/approve.py b/Powers/plugins/approve.py index 963d2512..9e9c667e 100644 --- a/Powers/plugins/approve.py +++ b/Powers/plugins/approve.py @@ -3,7 +3,7 @@ from pyrogram.errors import PeerIdInvalid, RPCError, UserNotParticipant from pyrogram.types import CallbackQuery, Message -from Powers import LOGGER, SUPPORT_GROUP +from Powers import LOGGER from Powers.bot_class import Gojo from Powers.database.approve_db import Approve from Powers.utils.custom_filters import admin_filter, command, owner_filter @@ -36,7 +36,7 @@ async def approve_user(c: Gojo, m: Message): except RPCError as ef: await m.reply_text( - f"Error: {ef}\nReport it to @{SUPPORT_GROUP}", + f"Error: {ef}\nReport it using /bug", ) return if member.status in (CMS.ADMINISTRATOR, CMS.OWNER): @@ -95,7 +95,7 @@ async def disapprove_user(c: Gojo, m: Message): return except RPCError as ef: await m.reply_text( - f"Error: {ef}\nReport it to @{SUPPORT_GROUP}", + f"Error: {ef}\nReport it using /bug", ) return @@ -210,12 +210,7 @@ async def unapproveall_callback(_, q: CallbackQuery): show_alert=True, ) return - if user_status != "creator": - await q.answer( - "You're just an admin, not owner\nStay in your limits!", - show_alert=True, - ) - return + db.unapprove_all() for i in approved_people: await q.message.chat.restrict_member( diff --git a/Powers/plugins/auto_join.py b/Powers/plugins/auto_join.py new file mode 100644 index 00000000..b3879ba7 --- /dev/null +++ b/Powers/plugins/auto_join.py @@ -0,0 +1,147 @@ +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.bot_class import Gojo +from Powers.database.autojoin_db import AUTOJOIN +from Powers.supports import get_support_staff +from Powers.utils.custom_filters import admin_filter, command + +SUPPORT_STAFF = get_support_staff() + +@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() + + 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(filters.group) +async def join_request_handler(c: Gojo, j: ChatJoinRequest): + chat = j.chat.id + aj = AUTOJOIN() + join_type = aj.get_autojoin(chat) + + if not join_type: + return + + user = j.from_user.id + userr = j.from_user + if join_type == "auto" or user in SUPPORT_STAFF: + await c.approve_chat_join_request(chat,user) + + elif join_type == "manual": + txt = "New join request is available\n**USER's INFO**\n" + txt += f"Name: {userr.first_name} {userr.last_name if userr.last_name else ''}" + 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 + 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 + + split = q.data.split("_") + chat = q.message.chat.id + user = int(split[-1]) + data = split[0] + + if data == "accept": + await c.approve_chat_join_request(chat,user) + await q.answer(f"APPROVED: {user}",True) + elif data == "decline": + await c.decline_chat_join_request(chat,user) + await q.answer(f"DECLINED: {user}") + + 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 36d7f4db..77546880 100644 --- a/Powers/plugins/bans.py +++ b/Powers/plugins/bans.py @@ -9,8 +9,9 @@ InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID, SUPPORT_STAFF +from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID 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 @@ -19,6 +20,7 @@ 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): @@ -93,8 +95,6 @@ async def tban_usr(c: Gojo, m: Message): txt = t_t[0] # Done this bcuz idk why t_t is tuple type data. SO now if it is tuple this will get text from it if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" if time_val: txt += f"\nBanned for:{time_val}" keyboard = InlineKeyboardMarkup( @@ -309,9 +309,6 @@ async def dtban_usr(c: Gojo, m: Message): txt = f"{admin} banned {banned} in {chat_title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" - if bantime: txt += f"\nBanned for: {time_val}" keyboard = InlineKeyboardMarkup( @@ -420,8 +417,6 @@ async def kick_usr(c: Gojo, m: Message): txt = f"{admin} kicked {kicked} in {chat_title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" # await m.reply_text(txt, reply_to_message_id=r_id) kickk = choice(KICK_GIFS) try: @@ -580,8 +575,6 @@ async def dkick_usr(c: Gojo, m: Message): txt = f"{admin} kicked {kicked} in {chat_title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" kickk = choice(KICK_GIFS) try: await m.reply_animation( @@ -656,12 +649,10 @@ async def unban_usr(c: Gojo, m: Message): await m.chat.unban_member(user_id) admin = m.from_user.mention unbanned = await mention_html(user_first_name, user_id) - chat_title = (m.chat.title,) + chat_title = m.chat.title txt = f"{admin} unbanned {unbanned} in chat {chat_title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" await m.reply_text(txt) except ChatAdminRequired: await m.reply_text(text="I'm not admin or I don't have rights.") @@ -809,8 +800,6 @@ async def dban_usr(c: Gojo, m: Message): txt = f"{m.from_user.mention} banned {m.reply_to_message.from_user.mention} in {m.chat.title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" keyboard = InlineKeyboardMarkup( [ [ @@ -914,8 +903,7 @@ async def ban_usr(c: Gojo, m: Message): txt = f"{m.from_user.mention} banned {banned} in {m.chat.title}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" + keyboard = InlineKeyboardMarkup( [ [ @@ -1019,8 +1007,6 @@ async def kickme(c: Gojo, m: Message): txt = "Why not let me help you!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" await m.reply_animation(animation=str(choice(KICK_GIFS)), caption=txt) await m.chat.unban_member(m.from_user.id) except RPCError as ef: diff --git a/Powers/plugins/birthday.py b/Powers/plugins/birthday.py index 1d23711e..24696eca 100644 --- a/Powers/plugins/birthday.py +++ b/Powers/plugins/birthday.py @@ -1,8 +1,6 @@ -from datetime import date, datetime, time -from random import choice +from datetime import date, datetime from traceback import format_exc -from apscheduler.schedulers.asyncio import AsyncIOScheduler from pyrogram import filters from pyrogram.enums import ChatMemberStatus, ChatType from pyrogram.types import CallbackQuery @@ -18,7 +16,6 @@ from Powers.plugins import bday_cinfo, bday_info from Powers.utils.custom_filters import command -from Powers.utils.extras import birthday_wish def give_date(date,form = "%d/%m/%Y"): @@ -144,7 +141,7 @@ async def who_is_next(c: Gojo, m: Message): break if not users: await xx.delete() - await m.reply_text("No birthdays found :/") + await m.reply_text("There are no upcoming birthdays of any user in this chat:/\nEither all the birthdays are passed or no user from this chat have registered their birthday") return txt = "🎊 Upcomming Birthdays Are 🎊\n" for i in users: @@ -186,6 +183,7 @@ async def cant_recall_it(c: Gojo, m: Message): 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"\n\nBirthday on: {result['dob']}" await m.reply_text(txt) return @@ -227,60 +225,7 @@ async def switch_on_off(c:Gojo, q: CallbackQuery): await q.edit_message_text(f"Done! I will {'wish' if data == 'yes' else 'not wish'}",reply_markup=IKM([[IKB("Close", "f_close")]])) return -scheduler = AsyncIOScheduler() -scheduler.timezone = TIME_ZONE -scheduler_time = time(0,0,0) -async def send_wishish(JJK: Gojo): - c_list = Chats.list_chats_by_id() - blist = list(bday_info.find()) - curr = datetime.now(TIME_ZONE).date() - cclist = list(bday_cinfo.find()) - for i in blist: - dob = give_date(i["dob"]) - if dob.month == curr.month and dob.day == curr.day: - for j in c_list: - if cclist and (j in cclist): - return - try: - 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" - else: - agee = f"{agee}th" - 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]: - xXx = await JJK.send_message(j,f"Happy {agee} birthday {U.user.mention}🥳\n{wish}") - try: - await xXx.pin() - except Exception: - pass - except Exception: - pass -"""" -from datetime import date, datetime - -#form = -num = "18/05/2005" -st = "18 May 2005" -timm = datetime.strptime(num,"%d/%m/%Y").date() -x = datetime.now().date() -if timm.month < x.month: - next_b = date(x.year + 1, timm.month, timm.day) - days_left = (next_b - x).days -else: - timmm = date(x.year, timm.month, timm.day) - days_left = (timmm - x).days -print(days_left) -print(x.year - timm.year) -""" __PLUGIN__ = "birthday" diff --git a/Powers/plugins/botstaff.py b/Powers/plugins/botstaff.py index 6c547bb5..a19ab60d 100644 --- a/Powers/plugins/botstaff.py +++ b/Powers/plugins/botstaff.py @@ -1,11 +1,14 @@ from pyrogram.errors import RPCError from pyrogram.types import Message -from Powers import DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS, WHITELIST_USERS +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): diff --git a/Powers/plugins/captcha.py b/Powers/plugins/captcha.py new file mode 100644 index 00000000..4ea390b8 --- /dev/null +++ b/Powers/plugins/captcha.py @@ -0,0 +1,234 @@ +from random import shuffle +from traceback import format_exc + +import pyrogram # don't remove +from pyrogram import filters +from pyrogram.enums import ChatMemberStatus as CMS +from pyrogram.types import CallbackQuery, ChatMemberUpdated, ChatPermissions +from pyrogram.types import InlineKeyboardButton as ikb +from pyrogram.types import InlineKeyboardMarkup as ikm +from pyrogram.types import Message + +from Powers import LOGGER +from Powers.bot_class import Gojo +from Powers.database.captcha_db import CAPTCHA, CAPTCHA_DATA +from Powers.supports import get_support_staff +from Powers.utils.captcha_helper import (genrator, get_image_captcha, + get_qr_captcha) +from Powers.utils.custom_filters import admin_filter, command + +SUPPORT_STAFF = get_support_staff() + +@Gojo.on_message(command("captcha") & admin_filter & ~filters.private) +async def start_captcha(c: Gojo, 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": + 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_chat_member_updated(filters.group,18) +async def joinss(c: Gojo, u: ChatMemberUpdated): + chat = u.chat.id + + if ( + u.new_chat_member + ): + pass + else: + return + + user = u.new_chat_member.user.id + userr = u.new_chat_member.user + + is_qr = CAPTCHA().is_captcha(chat) + if not is_qr: + return + + captcha = CAPTCHA() + cap_data = CAPTCHA_DATA() + + if user in SUPPORT_STAFF: + return + + captcha_type = captcha.get_captcha(chat) + + is_already = cap_data.is_already_data(chat, user) + + 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 not mess: + cap_data.del_message_id(chat,is_already) + return + + try: + await c.restrict_chat_member(chat,user,ChatPermissions()) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + return + + if not is_already: + if captcha_type == "qr": + pic = await get_qr_captcha(chat, user) + cap = f"Please {userr.mention} scan this qr code with your phone to verify that you are human" + ms = await c.send_photo(chat,pic,caption=cap) + cap_data.store_message_id(chat,user,ms.id) + return + elif captcha_type == "image": + img, code = await get_image_captcha(chat, user) + cap = f"Please {userr.mention} please choose the correct code from the one given bellow\nYou have three tries if you get all three wrong u will be kicked from the chat.\nTries left: 3" + cap_data.load_cap_data(chat, user, code) + rand = [code] + while len(rand) != 5: + hehe = genrator() + rand.append(hehe) + + shuffle(rand) + + ini = f"captcha_{chat}_{user}_" + + 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) + return + elif is_already and mess: + kb = ikm( + [ + [ + ikb("Click here to verify",url=mess.link) + ] + ] + ) + await c.send_message(f"{userr.mention} your verification is already pending",reply_markup=kb) + return + else: + await c.unban_chat_member(chat,user) + 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: + new_cap = f"You have zero tries left now. I am going to kick you know coz you failed to solve captcha...see yaa {q.from_user.mention}" + try: + await q.message.chat.ban_member(user) + except Exception as e: + await q.message.reply_text("Failed to kick member") + return + await q.message.delete() + await q.message.reply_text(new_cap) + await c.unban_chat_member(chat,user) + + else: + await q.edit_message_caption(new_cap,reply_markup=q.message.reply_markup) + return + + +__PLUGIN__ = "captcha" + +__HELP__ = """ +• /captcha [on|yes|enable|off|no|disable] : To enable or disable captcha verification +• /captchamode [qr|image] : To change captcha mode +""" \ No newline at end of file diff --git a/Powers/plugins/dev.py b/Powers/plugins/dev.py index 1f60783d..3a7e47dd 100644 --- a/Powers/plugins/dev.py +++ b/Powers/plugins/dev.py @@ -7,58 +7,192 @@ from time import gmtime, strftime, time from traceback import format_exc +from pyrogram import filters from pyrogram.errors import (ChannelInvalid, ChannelPrivate, ChatAdminRequired, EntityBoundsInvalid, FloodWait, MessageTooLong, PeerIdInvalid, RPCError) +from pyrogram.types import InlineKeyboardButton as IKB +from pyrogram.types import InlineKeyboardMarkup as IKM from pyrogram.types import Message -from Powers import (BOT_TOKEN, DEV_USERS, LOG_DATETIME, LOGFILE, LOGGER, - MESSAGE_DUMP, OWNER_ID, UPTIME) +from Powers import (BOT_TOKEN, LOG_DATETIME, LOGFILE, LOGGER, MESSAGE_DUMP, + OWNER_ID, UPTIME) from Powers.bot_class import Gojo from Powers.database import MongoDB from Powers.database.chats_db import Chats -from Powers.plugins.clean_db import clean_my_db +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 from Powers.utils.parser import mention_markdown -@Gojo.on_message(command(["adddev", "rmdev"])) -async def add_dev(c: Gojo, m:Message): - if m.from_user.id != OWNER_ID: - await m.reply_text("Only owner can do that") +def can_change_type(curr, to_user): + if curr == "dev" and to_user in ["whitelist","sudo"]: + return True + elif curr == "sudo" and to_user == "whitelist": + return True + else: + return False + +@Gojo.on_message(command(["addsupport"])) +async def add_support(c: Gojo, m:Message): + support = SUPPORTS() + curr_user = support.get_support_type(m.from_user.id) + if not curr_user: + await m.reply_text("Stay in you limit") return - split = m.text.split(None) + split = m.command reply_to = m.reply_to_message - if len(split) != 2: - if not reply_to: - await m.reply_text("Reply to message to add the user in dev") + if reply_to: + try: + userr = reply_to.from_user.id + except Exception: + await m.reply_text("Reply to an user") + return + curr = support.get_support_type(userr) + try: + to = split[1].lower() + except IndexError: + await m.reply_text("**USAGE**\n/addsupport [reply to message | user id] [dev | sudo | whitelist]") + return + if to not in ["dev","sudo","whitelist"]: + await m.reply_text("**USAGE**\n/addsupport [reply to message | user id] [dev | sudo | whitelist]") + return + if m.from_user.id == int(OWNER_ID): + if to == curr: + await m.reply_text(f"This user is already in {to} users") + return + elif curr: + kb = IKM( + [ + [ + IKB("Yes",f"change_support_type:{to}"), + IKB("No","change_support_type:no") + ] + ] + ) + await m.reply_text(f"This is user is already in {curr} users\nDo you want to make him {to} user?",reply_markup=kb) + return + else: + support.insert_support_user(userr,to) + await m.reply_text(f"This user is now a {to} user") + return + can_do = can_change_type(curr_user,to) + if can_do: + if to == curr: + await m.reply_text(f"This user is already in {to} users") + return + elif curr: + kb = IKM( + [ + [ + IKB("Yes",f"change_support_type:{to}"), + IKB("No","change_support_type:no") + ] + ] + ) + await m.reply_text(f"This is user is already in {curr} users\nDo you want to make him {to} user?",reply_markup=kb) + return + else: + support.insert_support_user(userr,to) + await m.reply_text(f"This user is now a {to} user") + return + else: + await m.reply_text("Sorry you can't do it") return - if not reply_to: - if len(split) != 2: - await m.reply_text("Give me an id") - return - elif reply_to: - user = reply_to.from_user.id - elif len(split) == 2: + elif len(split) >= 3: + user = split[1] try: - user,_,_ = extract_user(c,m) - except Exception as e: - await m.reply_text(f"Give me id of the user {e}") + userr,_,_ = extract_user(user) + except Exception: + await m.reply_text("Tell the user to start me first") return - if m.command[0] == "rmdev": + curr = support.get_support_type(userr) try: - DEV_USERS.remove(user) - await m.reply_text(f"Removed {user} from dev") + to = m.command[2].lower() + except IndexError: + await m.reply_text("**USAGE**\n/addsupport [reply to message | user id | username] [dev | sudo | whitelist]") + return + if to not in ["dev","sudo","whitelist"]: + await m.reply_text("**USAGE**\n/addsupport [reply to message | user id] [dev | sudo | whitelist]") return - except ValueError: - await m.reply_text("User is not a dev") + if m.from_user.id == int(OWNER_ID): + if to == curr: + await m.reply_text(f"This user is already in {to} users") + return + elif curr: + kb = IKM( + [ + [ + IKB("Yes",f"change_support_type:{to}"), + IKB("No","change_support_type:no") + ] + ] + ) + await m.reply_text(f"This is user is already in {curr} users\nDo you want to make him {to} user?",reply_markup=kb) + return + else: + support.insert_support_user(userr,to) + await m.reply_text(f"This user is now a {to} user") + return + can_do = can_change_type(curr_user,to) + if can_do: + if to == curr: + await m.reply_text(f"This user is already in {to} users") + return + elif curr: + kb = IKM( + [ + [ + IKB("Yes",f"change_support_type:{to}"), + IKB("No","change_support_type:no") + ] + ] + ) + await m.reply_text(f"This is user is already in {curr} users\nDo you want to make him {to} user?",reply_markup=kb) + return + else: + support.insert_support_user(userr,to) + await m.reply_text(f"This user is now a {to} user") + return + else: + await m.reply_text("Sorry you can't do it") return - DEV_USERS.append(user) - await m.reply_text(f"Added {user} to dev") + +@Gojo.on_message(command("rmsupport")) +async def rm_support(c: Gojo, m: Message): + support = SUPPORTS() + curr_user = support.get_support_type(m.from_user.id) + if not curr_user: + await m.reply_text("Stay in you limit") + return + split = m.command + reply_to = m.reply_to_message + + if reply_to: + try: + curr = reply_to.from_user.id + except Exception: + await m.reply_text("Reply to an user") + return + support.delete_support_user(curr) + await m.reply_text("Done! User now no longer belongs to the support staff") + elif len(split) >= 2: + try: + user,_,_ = extract_user(split[1]) + except Exception: + await m.reply_text("Dunno who u r talking abt") + return + support.delete_support_user(user) + await m.reply_text("Done! User now no longer belongs to the support staff") + else: + await m.reply_text("**USAGE**\n/rmsupport [reply to user | user id | username]") return - + @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}") @@ -199,7 +333,7 @@ async def evaluate_code(c: Gojo, m: Message): f"@{m.from_user.username} TREID TO FETCH ENV OF BOT \n userid = {m.from_user.id}", ) for j in HARMFUL: - if j in evaluation: + if j in evaluation.split() or j in cmd: if m.from_user.id != OWNER_ID: evaluation = "Bhaag ja bsdk" await c.send_message( @@ -480,6 +614,58 @@ async def chat_broadcast(c: Gojo, m: Message): return +@Gojo.on_message(command(["forward","fwd"],dev_cmd=True)) +async def forward_type_broadcast(c: Gojo, m: Message): + repl = m.reply_to_message + if not repl: + await m.reply_text("Please reply to message to broadcast it") + return + split = m.command + + chat = Chats.list_chats_by_id() + user = [i["_id"] for i in Users.list_users()] + alll = chat + user + if len(split) != 2: + tag = "all" + else: + try: + if split[0].lower() == "-u": + tag = "user" + elif split[0].lower() == "-c": + tag = "chat" + else: + tag = "all" + except IndexError: + pass + if tag == "chat": + peers = chat + elif tag == "user": + peers = user + else: + peers = alll + + xx = await m.reply_text("Broadcasting...") + + failed = 0 + total = len(peers) + for peer in peers: + try: + await repl.forward(int(peer)) + await sleep(0.1) + except Exception: + failed += 1 + pass + txt = f"Broadcasted message to {total-failed} peers out of {total}\nFailed to broadcast message to {failed} peers" + if not failed: + txt = f"Broadcasted message to {total} peers" + await m.reply_text(txt) + try: + await xx.delete() + except Exception: + pass + 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...") @@ -509,7 +695,7 @@ async def cleeeen(c:Gojo,m:Message): • /update : To update the bot with the main stream repo **Dev's commands:** -• /adddev : Reply to message or give me user id or username +• /addsupport [dev | sudo | whitelist] : Reply to message or give me user id or username • /logs : Return the logs of bot. • /neofetch : Fetch neo. • /eval : Evaluate the given python code. @@ -518,6 +704,11 @@ async def cleeeen(c:Gojo,m:Message): • /uptime : Return the uptime of the bot. • /leavechat : Bot will leave the provided chat. • /chatbroadcast : Broadcast the messge to chats. +• /forward (/fwd) [tag] : Forward message to peers according to tag. Default to all + Available tags: + `-u` : For users + `-c` : For chats + `-all` : For all **Sudoer's command:** • /ping : return the ping of the bot. diff --git a/Powers/plugins/filters.py b/Powers/plugins/filters.py index b044a341..78e23e1d 100644 --- a/Powers/plugins/filters.py +++ b/Powers/plugins/filters.py @@ -212,7 +212,7 @@ async def send_filter_reply(c: Gojo, m: Message, trigger: str): text = await escape_mentions_using_curly_brackets(m, filter_reply, parse_words) teks, button = await parse_button(text) button = await build_keyboard(button) - button = InlineKeyboardMarkup(button) if button else None + button = ikb(button) if button else None textt = teks try: if msgtype == Types.TEXT: diff --git a/Powers/plugins/flood.py b/Powers/plugins/flood.py index c883b672..5cff9e76 100644 --- a/Powers/plugins/flood.py +++ b/Powers/plugins/flood.py @@ -10,15 +10,18 @@ InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, SUPPORT_GROUP, SUPPORT_STAFF +from Powers import LOGGER, SUPPORT_GROUP 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.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"] @@ -408,7 +411,7 @@ async def flood_watcher(c: Gojo, m: Message): ], ], ) - txt = "Don't dare to spam here if I am around!" + txt = "Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: Baned\nReason: Spaming" await m.reply_animation( animation=str(choice(BAN_GIFS)), caption=txt, @@ -440,7 +443,7 @@ 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!" + txt = "Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: kicked\nReason: Spaming" await m.reply_animation( animation=str(choice(KICK_GIFS)), caption=txt, @@ -483,7 +486,7 @@ async def flood_watcher(c: Gojo, m: Message): ], ], ) - txt = "Don't dare to spam here if I am around!" + txt = "Don't dare to spam here if I am around! Nothing can escape my 6 eyes\nAction: Muted\nReason: Spaming" await m.reply_animation( animation=str(choice(MUTE_GIFS)), caption=txt, diff --git a/Powers/plugins/fun.py b/Powers/plugins/fun.py index 9624643a..42e56f58 100644 --- a/Powers/plugins/fun.py +++ b/Powers/plugins/fun.py @@ -5,13 +5,15 @@ from pyrogram.errors import MessageTooLong from pyrogram.types import Message -from Powers import DEV_USERS, LOGGER +from Powers import LOGGER 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): diff --git a/Powers/plugins/greetings.py b/Powers/plugins/greetings.py index e0ac1e14..e5bc2df2 100644 --- a/Powers/plugins/greetings.py +++ b/Powers/plugins/greetings.py @@ -1,17 +1,20 @@ from html import escape from secrets import choice +from traceback import format_exc from pyrogram import enums, filters from pyrogram.enums import ChatMemberStatus as CMS from pyrogram.errors import ChatAdminRequired, RPCError -from pyrogram.types import ChatMemberUpdated, InlineKeyboardMarkup, Message +from pyrogram.types import ChatMemberUpdated, Message -from Powers import DEV_USERS +from Powers import 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.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, @@ -21,6 +24,8 @@ # Initialize gdb = GBan() +DEV_USERS = get_support_staff("dev") + ChatType = enums.ChatType @@ -159,7 +164,7 @@ async def save_wlcm(_, m: Message): await m.reply_text("Please provide some data for this to reply with!") return - db.set_welcome_text(text,file) + db.set_welcome_text(text,msgtype,file) await m.reply_text("Saved welcome!") return @@ -197,7 +202,7 @@ async def save_gdbye(_, m: Message): await m.reply_text("Please provide some data for this to reply with!") return - db.set_goodbye_text(text,file) + db.set_goodbye_text(text,msgtype,file) await m.reply_text("Saved goodbye!") return @@ -289,7 +294,7 @@ async def member_has_joined(c: Gojo, member: ChatMemberUpdated): if status: tek, button = await parse_button(hmm) button = await build_keyboard(button) - button = InlineKeyboardMarkup(button) if button else None + button = ikb(button) if button else None if "%%%" in tek: filter_reply = tek.split("%%%") @@ -322,7 +327,8 @@ async def member_has_joined(c: Gojo, member: ChatMemberUpdated): if jj: db.set_cleanwlcm_id(int(jj.id)) except RPCError as e: - print(e) + LOGGER.error(e) + LOGGER.error(format_exc(e)) return else: return @@ -360,7 +366,7 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): if status: tek, button = await parse_button(hmm) button = await build_keyboard(button) - button = InlineKeyboardMarkup(button) if button else None + button = ikb(button) if button else None if "%%%" in tek: filter_reply = tek.split("%%%") @@ -400,7 +406,8 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): db.set_cleangoodbye_id(int(ooo.id)) return except RPCError as e: - print(e) + LOGGER.error(e) + LOGGER.error(format_exc(e)) return else: return @@ -432,11 +439,11 @@ async def welcome(c: Gojo, m: Message): return if args[1].lower() == "on": db.set_current_welcome_settings(True) - await m.reply_text("Turned on!") + await m.reply_text("I will greet newly joined member from now on.") return if args[1].lower() == "off": db.set_current_welcome_settings(False) - await m.reply_text("Turned off!") + await m.reply_text("I will stay quiet when someone joins.") return await m.reply_text("what are you trying to do ??") return @@ -448,10 +455,25 @@ async def welcome(c: Gojo, m: Message): Welcome text: """, ) + UwU = db.get_welcome_media() + mtype = db.get_welcome_msgtype() tek, button = await parse_button(oo) button = await build_keyboard(button) - button = InlineKeyboardMarkup(button) if button else None - await c.send_message(m.chat.id, text=tek, reply_markup=button) + button = ikb(button) if button else None + if not UwU: + await c.send_message( + m.chat.id, + text=tek, + reply_markup=button, + disable_web_page_preview=True, + ) + elif UwU: + await (await send_cmd(c,mtype))( + m.chat.id, + UwU, + caption=tek, + reply_markup=button, + ) return @@ -479,11 +501,11 @@ async def goodbye(c: Gojo, m: Message): return if args[1].lower() == "on": db.set_current_goodbye_settings(True) - await m.reply_text("Turned on!") + await m.reply_text("I don't want but I will say goodbye to the fugitives") return if args[1].lower() == "off": db.set_current_goodbye_settings(False) - await m.reply_text("Turned off!") + await m.reply_text("I will stay quiet for fugitives") return await m.reply_text("what are you trying to do ??") return @@ -495,10 +517,26 @@ async def goodbye(c: Gojo, m: Message): Goodbye text: """, ) + UwU = db.get_goodbye_media() + mtype = db.get_goodbye_msgtype() tek, button = await parse_button(oo) button = await build_keyboard(button) - button = InlineKeyboardMarkup(button) if button else None - await c.send_message(m.chat.id, text=tek, reply_markup=button) + button = ikb(button) if button else None + if not UwU: + await c.send_message( + m.chat.id, + text=tek, + reply_markup=button, + disable_web_page_preview=True, + ) + elif UwU: + await (await send_cmd(c,mtype))( + m.chat.id, + UwU, + caption=tek, + reply_markup=button, + ) + return return diff --git a/Powers/plugins/info.py b/Powers/plugins/info.py index 2ef9156e..9ef892bb 100644 --- a/Powers/plugins/info.py +++ b/Powers/plugins/info.py @@ -9,10 +9,10 @@ from pyrogram.raw.functions.users import GetFullUser from pyrogram.types import Message -from Powers import (DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS, SUPPORT_STAFF, - WHITELIST_USERS) +from Powers import LOGGER, OWNER_ID 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 @@ -83,6 +83,10 @@ 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") username = user.username first_name = user.first_name last_name = user.last_name diff --git a/Powers/plugins/locks.py b/Powers/plugins/locks.py index c268b19e..4d749b6d 100644 --- a/Powers/plugins/locks.py +++ b/Powers/plugins/locks.py @@ -6,43 +6,41 @@ from pyrogram.errors import ChatAdminRequired, ChatNotModified, RPCError from pyrogram.types import ChatPermissions, Message -from Powers import DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS +from Powers import LOGGER 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 = set(SUDO_USERS + DEV_USERS + [int(OWNER_ID)]) +SUDO_LEVEL = get_support_staff("sudo_level") + +l_t = """ +**Lock Types:** +- `all` = Everything +- `msg` = Messages +- `media` = Media, such as Photo and Video. +- `polls` = Polls +- `invite` = Add users to Group +- `pin` = Pin Messages +- `info` = Change Group Info +- `webprev` = Web Page Previews +- `inlinebots`, `inline` = Inline bots +- `animations` = Animations +- `games` = Game Bots +- `stickers` = Stickers +- `anonchannel` = Send as chat will be locked +- `forwardall` = Forwarding from channel and user +- `forwardu` = Forwarding from user +- `forwardc` = Forwarding from channel +- `links | url` = Lock links""" -anti_c_send = [-1001604479593] -anti_forward = [-1001604479593] -anti_forward_u = [] -anti_forward_c = [] -anti_links = [] @Gojo.on_message(command("locktypes")) async def lock_types(_, m: Message): await m.reply_text( - ( - "**Lock Types:**\n" - " - `all` = Everything\n" - " - `msg` = Messages\n" - " - `media` = Media, such as Photo and Video.\n" - " - `polls` = Polls\n" - " - `invite` = Add users to Group\n" - " - `pin` = Pin Messages\n" - " - `info` = Change Group Info\n" - " - `webprev` = Web Page Previews\n" - " - `inlinebots`, `inline` = Inline bots\n" - " - `animations` = Animations\n" - " - `games` = Game Bots\n" - " - `stickers` = Stickers\n" - " - `anonchannel` = Send as chat will be locked\n" - " - `forwardall` = Forwarding from channel and user\n" - " - `forwardu` = Forwarding from user\n" - " - `forwardc` = Forwarding from channel\n" - " - `links | url` = Lock links" - ), + l_t ) return @@ -82,6 +80,8 @@ async def lock_perm(c: Gojo, m: Message): await prevent_approved(m) return + lock = LOCKS() + if lock_type == "msg": msg = False perm = "messages" @@ -126,51 +126,36 @@ async def lock_perm(c: Gojo, m: Message): pin = False perm = "pin" elif lock_type in ["links", "url"]: - if not len(anti_links): - anti_links.append(m.chat.id) - elif m.chat.id not in anti_links: - anti_links.append(m.chat.id) - else: + curr = lock.insert_lock_channel(m.chat.id, "anti_links") + if not curr: await m.reply_text("It is already on") return await m.reply_text("Locked links in the chat") return elif lock_type == "anonchannel": - if not len(anti_c_send): - anti_c_send.append(m.chat.id) - elif m.chat.id not in anti_c_send: - anti_c_send.append(m.chat.id) - else: + 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": - if not len(anti_forward): - anti_forward.append(m.chat.id) - elif m.chat.id not in anti_forward: - anti_forward.append(m.chat.id) - else: + 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": - if not len(anti_forward_u): - anti_forward_u.append(m.chat.id) - elif m.chat.id not in anti_forward: - anti_forward_u.append(m.chat.id) - else: + 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": - if not len(anti_forward_c): - anti_forward_c.append(m.chat.id) - elif m.chat.id not in anti_forward: - anti_forward_c.append(m.chat.id) - else: + curr = lock.insert_lock_channel(m.chat.id,"anti_fwd_c") + if not curr: await m.reply_text("It is already on") return await m.reply_text("Locked Forward message from channel") @@ -218,6 +203,13 @@ async def convert_to_emoji(val: bool): if val: return "✅" 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 @@ -322,6 +314,8 @@ 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" @@ -366,57 +360,49 @@ async def unlock_perm(c: Gojo, m: Message): upin = True uperm = "pin" elif unlock_type == "anonchannel": - try: - if not len(anti_c_send) or m.chat.id not in anti_c_send: - await m.reply_text("Already off") - return - anti_c_send.remove(m.chat.id) - await m.reply_text("Send as chat is now enabled for this chat") - return - except ValueError: - await m.reply_text("It is already off") + 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"]: - try: - anti_links.remove(m.chat.id) + curr = lock.remove_lock_channel(m.chat.id,"anti_links") + if curr: await m.reply_text("Sending link is now allowed") return - except ValueError: - await m.reply_text("Already allowed") + else: + await m.reply_text("Sending link is not allowed") return elif unlock_type == "forwardall": - try: - if not len(anti_forward) or m.chat.id not in anti_forward: - await m.reply_text("Already off") - return - anti_forward.remove(m.chat.id) - await m.reply_text("Forwarding content is now enabled for this chat") - return - except ValueError: - await m.reply_text("It is already off") + 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": - try: - if not len(anti_forward_u) or m.chat.id not in anti_forward_u: - await m.reply_text("Already off") - return - anti_forward_u.remove(m.chat.id) - await m.reply_text("Forwarding content is now enabled for this chat") - return - except ValueError: - await m.reply_text("It is already off") + 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": - try: - if not len(anti_forward_c) or m.chat.id not in anti_forward_c: - await m.reply_text("Already off") - return - anti_forward_c.remove(m.chat.id) - await m.reply_text("Forwarding content is now enabled for this chat") - return - except ValueError: - await m.reply_text("It is already off") + 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! @@ -487,7 +473,10 @@ async def is_approved_user(c:Gojo, m: Message): @Gojo.on_message(filters.all & ~filters.me,18) async def lock_del_mess(c:Gojo, m: Message): - all_chats = anti_c_send + anti_forward + anti_forward_c + anti_forward_u + anti_links + lock = LOCKS() + all_chats = lock.get_lock_channel() + if not all_chats: + return if m.chat.id not in all_chats: return if m.sender_chat and not (m.forward_from_chat or m.forward_from): @@ -505,13 +494,13 @@ async def lock_del_mess(c:Gojo, m: Message): return elif m.forward_from or m.forward_from_chat: if not is_approved: - if m.chat.id in anti_forward: + if lock.is_particular_lock(m.chat.id,"anti_fwd"): await delete_messages(c,m) return - elif m.chat.id in anti_forward_u and not m.forward_from_chat: + elif lock.is_particular_lock(m.chat.id,"anti_fwd_u") and not m.forward_from_chat: await delete_messages(c,m) return - elif m.chat.id in anti_forward_c and m.forward_from_chat: + elif lock.is_particular_lock(m.chat.id,"anti_fwd_c") and m.forward_from_chat: await delete_messages(c,m) return @@ -532,6 +521,11 @@ async def prevent_approved(m: Message): __alt_name__ = ["grouplock", "lock", "grouplocks"] +__buttons__ = [ + [ + ("Lock Types", "LOCK_TYPES"), + ],] + __HELP__ = """ **Locks** diff --git a/Powers/plugins/muting.py b/Powers/plugins/muting.py index 6c84f7af..1b0a459d 100644 --- a/Powers/plugins/muting.py +++ b/Powers/plugins/muting.py @@ -9,8 +9,9 @@ InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID, SUPPORT_STAFF +from Powers import LOGGER, MESSAGE_DUMP, OWNER_ID 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 @@ -19,6 +20,7 @@ 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): @@ -90,8 +92,6 @@ async def tmute_usr(c: Gojo, m: Message): txt = f"Admin {admin} muted {muted}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" if mutetime: txt += f"\nMuted for: {time_val}" keyboard = InlineKeyboardMarkup( @@ -203,8 +203,6 @@ async def dtmute_usr(c: Gojo, m: Message): txt = f"Admin {admin} muted {muted}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" if mutetime: txt += f"\nMuted for: {time_val}" keyboard = InlineKeyboardMarkup( @@ -384,8 +382,6 @@ async def mute_usr(c: Gojo, m: Message): txt = f"Admin {admin} muted {muted}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" keyboard = InlineKeyboardMarkup( [ [ @@ -543,8 +539,6 @@ async def dmute_usr(c: Gojo, m: Message): txt = f"Admin {admin} muted {muted}!" if reason: txt += f"\nReason: {reason}" - else: - txt += "\nReason: Not Specified" keyboard = InlineKeyboardMarkup( [ [ diff --git a/Powers/plugins/pin.py b/Powers/plugins/pin.py index 85f374c5..1efad9e7 100644 --- a/Powers/plugins/pin.py +++ b/Powers/plugins/pin.py @@ -97,7 +97,7 @@ async def unpin_message(c: Gojo, m: Message): async def unpinall_message(_, m: Message): await m.reply_text( "Do you really want to unpin all messages in this chat?", - reply_markup=ikb([[("Yes", "unpin all in this chat"), ("No", "close_admin")]]), + reply_markup=ikb([[("Yes", "unpin_all_in_this_chat"), ("No", "close_admin")]]), ) return diff --git a/Powers/plugins/report.py b/Powers/plugins/report.py index f8b71974..0871fcb0 100644 --- a/Powers/plugins/report.py +++ b/Powers/plugins/report.py @@ -6,13 +6,15 @@ from pyrogram.errors import RPCError from pyrogram.types import CallbackQuery, Message -from Powers import LOGGER, SUPPORT_STAFF +from Powers import LOGGER 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), diff --git a/Powers/plugins/scheduled_jobs.py b/Powers/plugins/scheduled_jobs.py new file mode 100644 index 00000000..923cb743 --- /dev/null +++ b/Powers/plugins/scheduled_jobs.py @@ -0,0 +1,144 @@ +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.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 + + +if BDB_URI: + from Powers.plugins import bday_cinfo, bday_info + +from datetime import datetime, time +from random import choice + +from pyrogram.enums import ChatMemberStatus + +from Powers.utils.extras import birthday_wish + + +def give_date(date,form = "%d/%m/%Y"): + datee = datetime.strptime(date,form).date() + return datee + +scheduler = AsyncIOScheduler() +scheduler.timezone = TIME_ZONE +scheduler_time = time(0,0,0) +async def send_wishish(JJK: Client): + c_list = Chats.list_chats_by_id() + blist = list(bday_info.find()) + curr = datetime.now(TIME_ZONE).date() + cclist = list(bday_cinfo.find()) + for i in blist: + dob = give_date(i["dob"]) + if dob.month == curr.month and dob.day == curr.day: + for j in c_list: + if cclist and (j in cclist): + return + try: + 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" + else: + agee = f"{agee}th" + 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]: + xXx = await JJK.send_message(j,f"Happy {agee} birthday {U.user.mention}🥳\n{wish}") + try: + await xXx.pin() + except Exception: + pass + except Exception: + pass + +"""" +from datetime import date, datetime + +#form = +num = "18/05/2005" +st = "18 May 2005" +timm = datetime.strptime(num,"%d/%m/%Y").date() +x = datetime.now().date() +if timm.month < x.month: + next_b = date(x.year + 1, timm.month, timm.day) + days_left = (next_b - x).days +else: + timmm = date(x.year, timm.month, timm.day) + days_left = (timmm - x).days +print(days_left) +print(x.year - timm.year) +""" + diff --git a/Powers/plugins/search.py b/Powers/plugins/search.py index 46187514..1e0ee226 100644 --- a/Powers/plugins/search.py +++ b/Powers/plugins/search.py @@ -1,6 +1,6 @@ from traceback import format_exc -from pyrogram.types import Message +from pyrogram.types import InputMediaPhoto, Message from search_engine_parser.core.engines.google import Search as GoogleSearch from search_engine_parser.core.engines.myanimelist import Search as AnimeSearch from search_engine_parser.core.engines.stackoverflow import \ @@ -11,6 +11,7 @@ from Powers import LOGGER, SUPPORT_CHANNEL from Powers.bot_class import Gojo from Powers.utils.custom_filters import command +from Powers.utils.http_helper import * from Powers.utils.kbhelpers import ikb #have to add youtube @@ -225,6 +226,47 @@ async def stack_search(c: Gojo, m: Message): return +async def getText(message: Message): + # Credits: https://t.me/NovaXMod + # https://t.me/NovaXMod/98 + """Extract Text From Commands""" + text_to_return = message.text + if message.text is None: + return None + if " " in text_to_return: + try: + return message.text.split(None, 1)[1] + except IndexError: + return None + except Exception: + return None + else: + return None + +@Gojo.on_message(command(["images","imgs"])) +async def get_image_search(_, m: Message): + # Credits: https://t.me/NovaXMod + # https://t.me/NovaXMod/98 + query = await getText(m) + if not query: + await m.reply_text("**USAGE**\n /images [query]") + return + text = query.replace(" ", "%") + resp = get(f"https://nova-api-seven.vercel.app/api/images?name={text}") + if type(resp) == int: + await m.reply_text(f"Status code: {resp}\nUnable find any results regarding your query :/") + return + image_urls = resp.get("image_urls", [])[:10] + ab = await m.reply_text("Getting Your Images... Wait A Min..\nCredits: @NovaXMod") + Ok = [] + for a in image_urls: + Ok.append(InputMediaPhoto(a)) + try: + await m.reply_media_group(media=Ok) + await ab.delete() + except Exception: + await ab.edit("Error occurred while sending images. Please try again.") + __PLUGIN__ = "search" @@ -241,7 +283,7 @@ async def stack_search(c: Gojo, m: Message): • /google `` : Search the google for the given query. • /anime `` : Search myanimelist for the given query. • /stack `` : Search stackoverflow for the given query. - +• /images (/imgs) `` : Get the images regarding to your query **Example:** `/google pyrogram`: return top 5 reuslts. diff --git a/Powers/plugins/start.py b/Powers/plugins/start.py index 7b4d7235..eac20e36 100644 --- a/Powers/plugins/start.py +++ b/Powers/plugins/start.py @@ -1,3 +1,4 @@ +import os from random import choice from time import gmtime, strftime, time @@ -12,11 +13,13 @@ from Powers import (HELP_COMMANDS, LOGGER, PYROGRAM_VERSION, PYTHON_VERSION, UPTIME, VERSION) 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.start_utils import (gen_cmds_kb, gen_start_kb, get_help_msg, get_private_note, get_private_rules) +from Powers.utils.string import encode_decode from Powers.vars import Config @@ -103,10 +106,27 @@ async def start(c: Gojo, m: Message): quote=True, ) return + elif help_option.split("_",1)[0] == "qrcaptcha": + decoded = encode_decode(help_option.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)) + try: + os.remove(f"captcha_verification{chat}_{user}.png") + except Exception: + pass + return + except Exception: + return try: cpt = f""" Hey [{m.from_user.first_name}](http://t.me/{m.from_user.username})! I am Gojo ✨. -I'm here to help you manage your groups! +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! Join my [News Channel](https://t.me/gojo_bots_network) to get information on all the latest updates.""" @@ -145,7 +165,7 @@ async def start_back(_, q: CallbackQuery): try: cpt = f""" Hey [{q.from_user.first_name}](http://t.me/{q.from_user.username})! I am Gojo ✨. -I'm here to help you manage your groups! +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! Join my [News Channel](http://t.me/gojo_bots_network) to get information on all the latest updates.""" @@ -167,7 +187,7 @@ async def commands_menu(_, q: CallbackQuery): try: cpt = f""" Hey **[{q.from_user.first_name}](http://t.me/{q.from_user.username})**! I am Gojo✨. -I'm here to help you manage your groups! +I'm here to help you manage your group(s)! Commands available: × /start: Start the bot × /help: Give's you this message. @@ -240,7 +260,7 @@ async def help_menu(_, m: Message): keyboard = ikb(ou, True) msg = f""" Hey **[{m.from_user.first_name}](http://t.me/{m.from_user.username})**!I am Gojo✨. -I'm here to help you manage your groups! +I'm here to help you manage your group(s)! Commands available: × /start: Start the bot × /help: Give's you this message.""" diff --git a/Powers/plugins/stickers.py b/Powers/plugins/stickers.py index 4512ab3b..c4d96c10 100644 --- a/Powers/plugins/stickers.py +++ b/Powers/plugins/stickers.py @@ -1,4 +1,3 @@ -import imghdr import os from asyncio import gather from random import choice @@ -64,7 +63,7 @@ async def sticker_id_gib(c: Gojo, m: Message): async def kang(c:Gojo, m: Message): if not m.reply_to_message: return await m.reply_text("Reply to a sticker or image to kang it.") - elif not (m.reply_to_message.sticker or m.reply_to_message.photo or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0]=="image")): + elif not (m.reply_to_message.animation or m.reply_to_message.sticker or m.reply_to_message.photo or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0]in["image","video"])): return await m.reply_text("Reply to a sticker or image to kang it.") if not m.from_user: return await m.reply_text("You are anon admin, kang stickers in my pm.") @@ -92,9 +91,9 @@ async def kang(c:Gojo, m: Message): # Get the corresponding fileid, resize the file if necessary try: - if is_requ or m.reply_to_message.photo or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0]=="image"): + if is_requ or m.reply_to_message.video or m.reply_to_message.photo or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0]=="image"): sizee = (await get_file_size(m.reply_to_message)).split() - if (sizee[1] == "mb" and sizee > 10) or sizee[1] == "gb": + if (sizee[1] == "mb" and int(sizee[0]) > 10) or sizee[1] == "gb": await m.reply_text("File size is too big") return path = await m.reply_to_message.download() @@ -113,8 +112,17 @@ async def kang(c:Gojo, m: Message): LOGGER.error(format_exc()) return try: - if is_requ or not m.reply_to_message.sticker: + if is_requ or m.reply_to_message.animation or m.reply_to_message.video or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0] == "video"): # telegram doesn't allow animated and video sticker to be kanged as we do for normal stickers + if m.reply_to_message.animation or m.reply_to_message.video or (m.reply_to_message.document and m.reply_to_message.document.mime_type.split("/")[0] == "video"): + path = await Vsticker(c, m.reply_to_message) + SIZE = os.path.getsize(path) + if SIZE > 261120: + await m.reply_text("File is too big") + os.remove(path) + return + else: + path = await m.reply_to_message.download() sticker = await create_sticker( await upload_document( c, path, m.chat.id @@ -142,7 +150,7 @@ 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_in = m.reply_to_message.sticker st_type = "norm" is_anim = is_vid = False if st_in: @@ -154,6 +162,19 @@ async def kang(c:Gojo, m: Message): 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 @@ -279,29 +300,51 @@ 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}" - if not m.reply_to_message: - await m.reply_text("Reply to a sticker or file") - return repl = m.reply_to_message - if not (repl.sticker or repl.photo or (repl.document and repl.document.mime_type.split("/")[0]=="image")): - await m.reply_text("I only support conversion of plain stickers and images for now") + if not repl: + await m.reply_text("Reply to a sticker or file") return - if repl.sticker and (repl.sticker.is_video or repl.sticker.is_animated): - await m.reply_text("I only support conversion of plain stickers for now") + to_vid = False + if not (repl.animation or repl.video or repl.sticker or repl.photo or (repl.document and repl.document.mime_type.split("/")[0] in ["image","video"])): + await m.reply_text("I only support conversion of plain stickers, images, videos and animation for now") return + if repl.animation or repl.video or (repl.document and repl.document.mime_type.split("/")[0]=="video"): + to_vid = True x = await m.reply_text("Converting...") if repl.sticker: + if repl.sticker.is_animated: + upp = await repl.download() + up = tgs_to_gif(upp,True) + await x.delete() + await m.reply_animation(up,caption=Caption) + os.remove(up) + return + elif repl.sticker.is_video: + upp = await repl.download() + up = await webm_to_gif(upp) + await x.delete() + await m.reply_animation(up,caption=Caption) + os.remove(up) + return + else: + upp = await repl.download() + up = toimage(upp,is_direc=True) + await x.delete() + await m.reply_photo(up,caption=Caption) + os.remove(up) + return + elif repl.photo: upp = await repl.download() - up = toimage(upp,is_direc=True) + up = tosticker(upp,is_direc=True) await x.delete() - await m.reply_photo(up,caption=Caption) + await m.reply_sticker(up) os.remove(up) return - elif repl.photo: - upp = await repl.download() - up = tosticker(upp,is_direc=True) + + elif to_vid: + up = await Vsticker(c,repl) await x.delete() - await m.reply_sticker(up,caption=Caption) + await m.reply_sticker(up) os.remove(up) return @@ -315,7 +358,7 @@ async def get_sticker_from_file(c: Gojo, m: Message): **User Commands:** • /kang (/steal) : Reply to a sticker or any supported media • /stickerinfo (/stinfo) : Reply to any sticker to get it's info -• /getsticker (/getst) : Get sticker as photo or vice versa. +• /getsticker (/getst) : Get sticker as photo, gif or vice versa. • /stickerid (/stid) : Reply to any sticker to get it's id • /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. diff --git a/Powers/plugins/utils.py b/Powers/plugins/utils.py index d35ccccd..0dc983c2 100644 --- a/Powers/plugins/utils.py +++ b/Powers/plugins/utils.py @@ -14,6 +14,7 @@ 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 @@ -62,7 +63,7 @@ async def wiki(_, m: Message): @Gojo.on_message(command("gdpr")) async def gdpr_remove(_, m: Message): - if m.from_user.id in SUPPORT_STAFF: + if m.from_user.id in get_support_staff(): await m.reply_text( "You're in my support staff, I cannot do that unless you are no longer a part of it!", ) @@ -239,6 +240,11 @@ async def github(_, m: Message): return r = r.json() avtar = r.get("avatar_url", None) + if avtar: + avtar = avtar.rsplit("=",1) + avtar.pop(-1) + avtar.append("5") + avtar = "=".join(avtar) url = r.get("html_url", None) name = r.get("name", None) company = r.get("company", None) @@ -281,6 +287,12 @@ async def github(_, m: Message): if bio: REPLY += f"\n\n🎯 Bio: {bio}" + kb = InlineKeyboardMarkup( + [ + InlineKeyboardButton("") + ] + ) + if avtar: return await m.reply_photo(photo=f"{avtar}", caption=REPLY) await m.reply_text(REPLY) @@ -407,7 +419,6 @@ 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 - __PLUGIN__ = "utils" _DISABLE_CMDS_ = ["paste", "wiki", "id", "gifid", "tr", "github", "git", "bug"] __alt_name__ = ["util", "misc", "tools"] diff --git a/Powers/plugins/warns.py b/Powers/plugins/warns.py index 7bfd28cf..157de69f 100644 --- a/Powers/plugins/warns.py +++ b/Powers/plugins/warns.py @@ -6,17 +6,19 @@ InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import LOGGER, SUPPORT_STAFF, TIME_ZONE +from Powers import LOGGER, TIME_ZONE 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, diff --git a/Powers/plugins/watchers.py b/Powers/plugins/watchers.py index c5ccc589..b1124a0f 100644 --- a/Powers/plugins/watchers.py +++ b/Powers/plugins/watchers.py @@ -7,7 +7,7 @@ from pyrogram.errors import ChatAdminRequired, RPCError, UserAdminInvalid from pyrogram.types import ChatPermissions, Message -from Powers import LOGGER, MESSAGE_DUMP, SUPPORT_STAFF +from Powers import LOGGER, MESSAGE_DUMP from Powers.bot_class import Gojo from Powers.database.antispam_db import ANTISPAM_BANNED, GBan from Powers.database.approve_db import Approve @@ -15,13 +15,14 @@ from Powers.database.group_blacklist import BLACKLIST_CHATS from Powers.database.pins_db import Pins 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.parser import mention_html 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): diff --git a/Powers/plugins/web_con.py b/Powers/plugins/web_con.py index 14815d77..e2143cc7 100644 --- a/Powers/plugins/web_con.py +++ b/Powers/plugins/web_con.py @@ -262,7 +262,7 @@ async def song_down_up(c: Gojo, m: Message): query = splited XnX = await m.reply_text("⏳") try: - x = await youtube_downloader(c,m,query,is_direct,"a") + await youtube_downloader(c,m,query,is_direct,"a") await XnX.delete() return except KeyError: diff --git a/Powers/supports.py b/Powers/supports.py new file mode 100644 index 00000000..6bee9455 --- /dev/null +++ b/Powers/supports.py @@ -0,0 +1,35 @@ +from Powers import DEV_USERS, OWNER_ID, SUDO_USERS, WHITELIST_USERS +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") + for i in SUDO_USERS: + support.insert_support_user(int(i),"sudo") + for i in WHITELIST_USERS: + support.insert_support_user(int(i),"whitelist") + return + +def get_support_staff(want = "all"): + """ + dev, sudo, whitelist, dev_level, sudo_level, all + """ + support = SUPPORTS() + devs = support.get_particular_support("dev") + sudo = support.get_particular_support("sudo") + whitelist = support.get_particular_support("whitelist") + + if want in ["dev","dev_level"]: + wanted = devs + elif want == "sudo": + wanted = sudo + elif want == "whitelist": + wanted = whitelist + elif want == "sudo_level": + wanted = sudo + devs + else: + wanted = list(set([int(OWNER_ID)] + devs + sudo + whitelist)) + + return wanted \ No newline at end of file diff --git a/Powers/utils/admin_check.py b/Powers/utils/admin_check.py index d5a14c43..e83e5456 100644 --- a/Powers/utils/admin_check.py +++ b/Powers/utils/admin_check.py @@ -3,10 +3,8 @@ from pyrogram.enums import ChatMemberStatus as CMS 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)] +from Powers import LOGGER, OWNER_ID +from Powers.database.support_db import SUPPORTS async def admin_check(m: Message or CallbackQuery) -> bool: @@ -16,6 +14,11 @@ async def admin_check(m: Message or CallbackQuery) -> bool: if isinstance(m, CallbackQuery): user_id = m.message.from_user.id + support = SUPPORTS() + + SUDO_LEVEL = support.get_particular_support("sudo") + support.get_particular_support("dev") + [int(OWNER_ID)] + DEV_LEVEL = support.get_particular_support("dev") + [int(OWNER_ID)] + try: if user_id in SUDO_LEVEL: return True @@ -66,6 +69,10 @@ async def owner_check(m: Message or CallbackQuery) -> bool: user_id = m.message.from_user.id m = m.message + support = SUPPORTS() + + SUDO_LEVEL = support.get_particular_support("sudo") + support.get_particular_support("dev") + [int(OWNER_ID)] + try: if user_id in SUDO_LEVEL: return True diff --git a/Powers/utils/captcha_helper.py b/Powers/utils/captcha_helper.py new file mode 100644 index 00000000..204dd65c --- /dev/null +++ b/Powers/utils/captcha_helper.py @@ -0,0 +1,56 @@ +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): + encode = f"{chat}:{user}" + encoded = 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"] + rand_alpha = choice(alpha) + if_ = randint(0,1) + + if if_: + new_alpha = rand_alpha.upper() + else: + new_alpha = rand_alpha + + list_ = [new_alpha] + while len(list_) != 4: + xXx = randrange(0,9) + list_.append(xXx) + + str_ = "" + while len(str_) != 4: + OwO = choice(list_) + str_ += OwO + return str_ + +async def get_image_captcha(chat,user): + str_ = genrator() + captchaa.load_cap_data(chat,user,str_) + name = f"captcha_img_{chat}_{user}.png" + image = ImageCaptcha(280,90) + + cap = image.generate(str_) + image.write(str_,name) + + return name, str_ + + diff --git a/Powers/utils/custom_filters.py b/Powers/utils/custom_filters.py index 570a1477..5e9fc3a5 100644 --- a/Powers/utils/custom_filters.py +++ b/Powers/utils/custom_filters.py @@ -9,14 +9,12 @@ from pyrogram.filters import create from pyrogram.types import CallbackQuery, Message -from Powers import DEV_USERS, OWNER_ID, SUDO_USERS +from Powers import OWNER_ID, PREFIX_HANDLER from Powers.database.disable_db import Disabling +from Powers.supports import get_support_staff 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( commands: Union[str, List[str]], @@ -29,6 +27,8 @@ async def func(flt, _, m: Message): if not m: return + SUDO_LEVEL = get_support_staff("sudo_level") + DEV_LEVEL = get_support_staff("dev_level") date = m.edit_date if date: return # reaction @@ -61,7 +61,7 @@ async def func(flt, _, m: Message): if not text: return False regex = r"^[{prefix}](\w+)(@{bot_name})?(?: |$)(.*)".format( - prefix="|".join(escape(x) for x in Config.PREFIX_HANDLER), + prefix="|".join(escape(x) for x in PREFIX_HANDLER), bot_name=Config.BOT_USERNAME, ) matches = compile_re(regex).search(text) @@ -289,6 +289,7 @@ async def can_pin_message_func(_, __, m): return True # Bypass the bot devs, sudos and owner + SUDO_LEVEL = get_support_staff("sudo_level") if m.from_user.id in SUDO_LEVEL: return True diff --git a/Powers/utils/extras.py b/Powers/utils/extras.py index 0298db0f..a2d91fba 100644 --- a/Powers/utils/extras.py +++ b/Powers/utils/extras.py @@ -695,6 +695,15 @@ "https://graph.org/file/6d18195f6e0e55af91228.png", "https://i.imgur.com/8l6cByn.jpg", "https://graph.org/file/259a92d3482fc8627fe68.png", + "https://graph.org/file/d328fb0a7e30b866979d5.jpg", + "https://graph.org/file/cdbc22231afb0937e1a5d.jpg", + "https://graph.org/file/dd32af83434be92ef4f72.jpg", + "https://graph.org/file/9c97627158a8b6c23cd8b.jpg", + "https://graph.org/file/0bd63482afbc2844cb77d.jpg", + "https://graph.org/file/798a33ee39bca8014116c.jpg", + "https://graph.org/file/d0beb924887f45ab1c84e.jpg", + "https://graph.org/file/9e92625135caffcadcbae.jpg", + "https://graph.org/file/f377781fe8a1fe09fea55.jpg", ] diff --git a/Powers/utils/http_helper.py b/Powers/utils/http_helper.py index 8b9d68b5..04341217 100644 --- a/Powers/utils/http_helper.py +++ b/Powers/utils/http_helper.py @@ -6,6 +6,8 @@ def get(url: str, *args, **kwargs): resp = requests.get(url, *args, **kwargs) + if resp.status_code != 200: + return resp.status_code try: data = resp.json() except Exception: @@ -24,6 +26,8 @@ def head(url: str, *args, **kwargs): def post(url: str, *args, **kwargs): resp = requests.post(url, *args, **kwargs) + if resp.status_code != 200: + return resp.status_code try: data = resp.json() except Exception: diff --git a/Powers/utils/msg_types.py b/Powers/utils/msg_types.py index 75e1402c..69464dfd 100644 --- a/Powers/utils/msg_types.py +++ b/Powers/utils/msg_types.py @@ -50,7 +50,7 @@ async def get_note_type(m: Message): data_type = Types.STICKER elif m.reply_to_message.document: - if m.reply_to_message.document.mime_type == "application/x-bad-tgsticker": + if m.reply_to_message.document.mime_type in ["application/x-bad-tgsticker", "application/x-tgsticker"]: data_type = Types.ANIMATED_STICKER else: data_type = Types.DOCUMENT @@ -89,7 +89,7 @@ async def get_note_type(m: Message): async def get_filter_type(m: Message): """Get filter type.""" if len(m.text.split()) <= 1: - return None, None, None, None + return None, None, None data_type = None content = None @@ -118,7 +118,7 @@ async def get_filter_type(m: Message): data_type = Types.STICKER elif m.reply_to_message.document: - if m.reply_to_message.document.mime_type == "application/x-bad-tgsticker": + if m.reply_to_message.document.mime_type in ["application/x-bad-tgsticker", "application/x-tgsticker"]: data_type = Types.ANIMATED_STICKER else: data_type = Types.DOCUMENT @@ -163,7 +163,7 @@ async def get_wlcm_type(m: Message): raw_text = m.text.markdown if m.text else m.caption.markdown args = raw_text.split(None, 1) - if not m.reply_to_message and m.text and len(m.text.split()) >= 2: + if not m.reply_to_message and m.text and len(m.text.strip().split()) >= 2: content = None text = m.text.markdown.split(None, 1)[1] data_type = Types.TEXT @@ -180,15 +180,66 @@ async def get_wlcm_type(m: Message): if len(args) >= 1 and m.reply_to_message.text: # not caption, text data_type = Types.TEXT - elif m.reply_to_message.sticker: - content = m.reply_to_message.sticker.file_id - data_type = Types.STICKER + elif m.reply_to_message.document: + data_type = Types.DOCUMENT + content = m.reply_to_message.document.file_id + + elif m.reply_to_message.photo: + content = m.reply_to_message.photo.file_id # last elem = best quality + data_type = Types.PHOTO + + elif m.reply_to_message.audio: + content = m.reply_to_message.audio.file_id + data_type = Types.AUDIO + + elif m.reply_to_message.voice: + content = m.reply_to_message.voice.file_id + data_type = Types.VOICE + + elif m.reply_to_message.video: + content = m.reply_to_message.video.file_id + data_type = Types.VIDEO + + elif m.reply_to_message.video_note: + content = m.reply_to_message.video_note.file_id + data_type = Types.VIDEO_NOTE + + elif m.reply_to_message.animation: + content = m.reply_to_message.animation.file_id + data_type = Types.ANIMATION + + else: + text = None + data_type = None + content = None + + return text, data_type, content + +async def get_afk_type(m: Message): + data_type = None + content = None + raw_text = m.text.markdown if m.text else m.caption.markdown + args = raw_text.split(None, 1) + + if not m.reply_to_message and m.text and len(m.text.strip().split()) >= 2: + content = None + text = m.text.markdown.split(None, 1)[1] + data_type = Types.TEXT + + elif m.reply_to_message: + + if m.reply_to_message.text: + text = m.reply_to_message.text.markdown + elif m.reply_to_message.caption: + text = m.reply_to_message.caption.markdown + else: + text = "" + + if len(args) >= 1 and m.reply_to_message.text: # not caption, text + data_type = Types.TEXT elif m.reply_to_message.document: - if m.reply_to_message.document.mime_type == "application/x-bad-tgsticker": - data_type = Types.ANIMATED_STICKER - else: - data_type = Types.DOCUMENT + data_type = Types.DOCUMENT content = m.reply_to_message.document.file_id elif m.reply_to_message.photo: diff --git a/Powers/utils/start_utils.py b/Powers/utils/start_utils.py index 3cca40ce..6ff56041 100644 --- a/Powers/utils/start_utils.py +++ b/Powers/utils/start_utils.py @@ -72,8 +72,8 @@ async def gen_start_kb(q: Message or CallbackQuery): ], [ ( - "Join for GFx work", - "https://t.me/psy_Logos", + "Essential", + "https://t.me/+PcVYvdzNt4E1YjM1", "url", ), ( diff --git a/Powers/utils/sticker_help.py b/Powers/utils/sticker_help.py index 6f0af427..d7bfcfc5 100644 --- a/Powers/utils/sticker_help.py +++ b/Powers/utils/sticker_help.py @@ -8,10 +8,24 @@ from PIL import Image, ImageDraw, ImageFont from pyrogram import errors, raw from pyrogram.file_id import FileId +from pyrogram.types import Message from Powers.bot_class import Gojo +async def runcmd(cmd: str) -> Tuple[str, str, int, int]: + args = shlex.split(cmd) + process = await asyncio.create_subprocess_exec( + *args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + return ( + stdout.decode("utf-8", "replace").strip(), + stderr.decode("utf-8", "replace").strip(), + process.returncode, + process.pid, + ) + async def get_sticker_set_by_name( client: Gojo, name: str ) -> raw.base.messages.StickerSet: @@ -97,7 +111,39 @@ async def resize_file_to_sticker_size(file_path: str,length:int=512,width:int=51 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'" + elif video: + cmd = f"ffmpeg -i '{file}' -c copy 'gojo_satoru.gif'" + await runcmd(cmd) + 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 + elif file.video: + file = file.video + _width_ = file.width + _height_ = file.height + if _height_ > _width_: + _height_, _width_ = (512, -1) + else: + _height_, _width_ = (-1, 512) + file = await c.download_media(file) + await runcmd( + f"ffmpeg -to 00:00:02.900 -i '{file}' -vf scale={_width_}:{_height_} -c:v libvpx-vp9 -crf 30 -b:v 560k -maxrate 560k -bufsize 256k -an 'VideoSticker.webm'" + ) + os.remove(file) + return "VideoSticker.webm" async def upload_document( @@ -183,7 +229,7 @@ async def draw_meme(image_path: str, text: str, sticker: bool, fiill: str) -> li # img = Image.open(image_path) # i_width, i_height = img.size # m_font = ImageFont.truetype( -# "./extras/comic.ttf", int((70 / 640) * i_width) +# "./extras/comic.ttf", int(i_width / 11) # ) # if ";" in text: # upper_text, lower_text = text.split(";") diff --git a/Powers/utils/string.py b/Powers/utils/string.py index 487f408a..28932c8b 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 @@ -192,3 +193,24 @@ 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 \ No newline at end of file diff --git a/Powers/utils/web_helpers.py b/Powers/utils/web_helpers.py index f3d37024..77484e9e 100644 --- a/Powers/utils/web_helpers.py +++ b/Powers/utils/web_helpers.py @@ -1,13 +1,16 @@ import json import os +from traceback import format_exc from urllib import parse -import yt_dlp 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 Powers.bot_class import Gojo +from Powers.bot_class import LOGGER, MESSAGE_DUMP, Gojo from Powers.utils.http_helper import * @@ -22,6 +25,12 @@ async def get_file_size(file: Message): size = file.audio.file_size/1024 elif file.sticker: size = file.sticker.file_size/1024 + elif file.animation: + size = file.animation.file_size/1024 + elif file.voice: + 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" @@ -34,98 +43,30 @@ async def get_file_size(file: Message): return f"{round(size)} gb" -class GOJO_YTS: - """ - A class to fetch link of from youtube using the name provided - Creadit: Hellbot - """ - def __init__(self, search_terms: str, max_results=None): - self.search_terms = search_terms - self.max_results = max_results - self.videos = self._search() - - def _search(self): - encoded_search = parse.quote_plus(self.search_terms) - BASE_URL = "https://youtube.com" - url = f"{BASE_URL}/results?search_query={encoded_search}" - response = requests.get(url).text - while "ytInitialData" not in response: - response = requests.get(url).text - results = self._parse_html(response) - if self.max_results is not None and len(results) > self.max_results: - return results[: self.max_results] - return results - - def _parse_html(self, response): - results = [] - start = response.index("ytInitialData") + len("ytInitialData") + 3 - end = response.index("};", start) + 1 - json_str = response[start:end] - data = json.loads(json_str) - - videos = data["contents"]["twoColumnSearchResultsRenderer"]["primaryContents"][ - "sectionListRenderer" - ]["contents"][0]["itemSectionRenderer"]["contents"] - - for video in videos: - res = {} - if "videoRenderer" in video.keys(): - video_data = video.get("videoRenderer", {}) - res["id"] = video_data.get("videoId", None) - res["thumbnails"] = [ - thumb.get("url", None) - for thumb in video_data.get("thumbnail", {}).get("thumbnails", [{}]) - ] - res["title"] = ( - video_data.get("title", {}).get("runs", [[{}]])[0].get("text", None) - ) - res["long_desc"] = ( - video_data.get("descriptionSnippet", {}) - .get("runs", [{}])[0] - .get("text", None) - ) - res["channel"] = ( - video_data.get("longBylineText", {}) - .get("runs", [[{}]])[0] - .get("text", None) - ) - res["duration"] = video_data.get("lengthText", {}).get("simpleText", 0) - res["views"] = video_data.get("viewCountText", {}).get("simpleText", 0) - res["publish_time"] = video_data.get("publishedTimeText", {}).get( - "simpleText", 0 - ) - res["url_suffix"] = ( - video_data.get("navigationEndpoint", {}) - .get("commandMetadata", {}) - .get("webCommandMetadata", {}) - .get("url", None) - ) - results.append(res) - return results - - def to_dict(self, clear_cache=True): - result = self.videos - if clear_cache: - self.videos = "" - return result - - def to_json(self, clear_cache=True): - result = json.dumps({"videos": self.videos}) - if clear_cache: - self.videos = "" - return result - +def get_duration_in_sec(dur: str): + duration = dur.split(":") + if len(duration) == 2: + dur = (int(duration[0]) * 60) + int(duration[1]) + else: + dur = int(duration[0]) + return dur # Gets yt result of given query. -async def song_search(query, max_results=1): - try: - results = json.loads(GOJO_YTS(query, max_results=max_results).to_json()) - except KeyError: - return +async def song_search(query, is_direct, max_results=1): yt_dict = {} + try: + if is_direct: + vid = Video.getInfo(query) + query = vid["title"] + else: + query = query + videos = VideosSearch(query,max_results) + results = await videos.next() + except Exception as e: + print(e) nums = 1 - for i in results["videos"]: + for i in results["result"]: durr = i['duration'].split(":") if len(durr) == 3: hour_to_sec = int(durr[0])*60*60 @@ -136,12 +77,15 @@ async def song_search(query, max_results=1): total = minutes_to_sec + int(durr[1]) if not (total > 600): dict_form = { - "link": f"https://www.youtube.com{i['url_suffix']}", - "title": i['title'], - "views": i['views'], - "channel": i['channel'], - "duration": i['duration'], - "thumbnail": i['thumbnails'][0] + "link": i["link"], + "title": i["title"], + "views": i["viewCount"]["short"], + "channel": i["channel"]["link"], + "duration": i["accessibility"]['duration'], + "DURATION": i["duration"], + "thumbnail": i["richThumbnail"]["url"], + "published": i["publishedTime"], + "uploader": i ["channel"]["name"] } yt_dict.update({nums: dict_form}) nums += 1 @@ -149,7 +93,7 @@ async def song_search(query, max_results=1): pass return yt_dict -song_opts = { +"""song_opts = { "format": "bestaudio", "addmetadata": True, "key": "FFmpegMetadata", @@ -186,67 +130,76 @@ async def song_search(query, max_results=1): "outtmpl": "%(id)s.mp4", "logtostderr": False, "quiet": True, -} +}""" async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str): if type_ == "a": - opts = song_opts + # opts = song_opts video = False song = True elif type_ == "v": - opts = video_opts + # opts = video_opts video = True song = False - ydl = yt_dlp.YoutubeDL(opts) - if is_direct: - query = query - else: - dicti = await song_search(query, 1) - if not dicti: - await m.reply_text("File with duration less than or equals to 5 minutes is allowed only") - try: - query = dicti[1]['link'] - except KeyError: - z = "KeyError" - return z - FILE = ydl.extract_info(query,download=video) - if int(FILE['duration']) > 600: + # ydl = yt_dlp.YoutubeDL(opts) + dicti = await song_search(query, is_direct,1) + if not dicti and type(dicti) != str: await m.reply_text("File with duration less than or equals to 5 minutes is allowed only") - return - f_name = FILE['title'] - uploader = FILE['uploader'] - up_url = FILE['uploader_url'] - views = FILE['view_count'] + elif type(dicti) == str: + await m.reply_text(dicti) + return + try: + query = dicti[1]['link'] + except KeyError: + return + yt = YouTube(query) + dicti = dicti[1] + f_name = dicti["title"] + views = dicti["views"] + up_url = dicti["channel"] + uploader = dicti["uploader"] + dura = dicti["duration"] + thumb = dicti["thumbnail"] + vid_dur = get_duration_in_sec(dicti["DURATION"]) + published_on = dicti["published"] + thumb_ = await c.send_photo(-1001586309125,thumb) + # FILE = ydl.extract_info(query,download=video) url = query - if song: - f_down = ydl.prepare_filename(FILE) - f_path = f"{f_down}.mp3" - thumb = f"{f_down}.webp" - ydl.download([query]) - elif video: - f_path = open(f"{FILE['id']}.mp4","rb") + thumb = await thumb_.download() + await thumb_.delete() cap = f""" -✘ Name: `{f_name}` -✘ Views: `{views}` +⤷ Name: `{f_name}` +⤷ Duration: `{dura}` +⤷ Views: `{views}` +⤷ Published: `{published_on}` """ 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}") ] ] ) - if video: - await m.reply_video(f_path,caption=cap,reply_markup=kb,duration=int(FILE['duration'])) - os.remove(f"./{FILE['id']}.mp4") - return - elif song: - await m.reply_audio(f_path,caption=cap,reply_markup=kb,duration=int(FILE['duration']),thumb=thumb,title=f_name) + if song: + audio_stream= yt.streams.filter(only_audio=True).first() + f_path = audio_stream.download("/youtube_downloads") + file_path = f"/youtube_downloads/{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) + os.remove(file_path) os.remove(thumb) return - - + elif video: + video_stream = yt.streams.get_highest_resolution() + video_stream.download("/youtube_downloads",f"{f_name}.mp4") + file_path = f"/youtube_downloads/{f_name}.mp4" + await m.reply_video(file_path,caption=cap,reply_markup=kb,duration=vid_dur,thumb=thumb) + os.remove(file_path) + os.remove(thumb) + return \ No newline at end of file diff --git a/Powers/vars.py b/Powers/vars.py index 2002a9b6..5471a08e 100644 --- a/Powers/vars.py +++ b/Powers/vars.py @@ -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", default=-100)) + MESSAGE_DUMP = int(config("MESSAGE_DUMP")) DEV_USERS = [ int(i) for i in config( @@ -64,7 +64,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 = -100 # Your Private Group ID for logs + MESSAGE_DUMP = -100845454887 # Your Private Group ID for logs DEV_USERS = [] SUDO_USERS = [] WHITELIST_USERS = [] diff --git a/README.md b/README.md index 930c8c1d..62cc71c9 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,8 @@ If all works well, the bot should send a message to the MESSAGE_DUMP Group!---> `API_HASH` You can get your api hash [here](my.telegram.org) `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`. @@ -201,8 +203,6 @@ If all works well, the bot should send a message to the MESSAGE_DUMP Group!---> `SUPPORT_GROUP`: Your Telegram support group chat username that users can contact in case of a problem. -`MESSAGE_DUMP`: Event logs channel where the bot will send updates. Note that it should start with `-100`. - `PREFIX_HANDLER`: Something like '/' to execute commands. `SUPPORT_CHANNEL`: Your Telegram support channel username where users can see bot updates. diff --git a/Version/version 2.2.0.md b/Version/version 2.2.0.md new file mode 100644 index 00000000..09c7e58f --- /dev/null +++ b/Version/version 2.2.0.md @@ -0,0 +1,21 @@ +# V 2.1.1 +### Changes made: +- Added `AFK` support. +- Added `Captcha verification` for new joined members. +- Added support for `join request` in the chat. +- Now `lock types` will be stored in database. +- Improved **youtube support** to provide best quality. +- Now you can kang `video sticker` by replying to **videos** and **animations**. +- Added few commands for **devs**. +- Improved stability and few minor improvements. +- Few bug fixes. +- Bug known: 0 +- Deployed and tested locally + +## 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) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 066b08e8..59962912 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ 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" +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" @@ -15,12 +16,13 @@ pillow == 10.0.0 prettyconf==2.2.1 pyaes==1.6.1; python_version >= "3.6" and python_version < "4.0" pymongo==4.5.0 -pyroaddon==1.0.6 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") +pytube==15.0.0 pytz==2023.3 pyyaml==6.0.1; python_version >= "3.6" +qrcode==7.4.2 regex==2023.8.8; python_version >= "3.6" requests==2.31.0 rfc3986==1.5.0; python_version >= "3.7" @@ -35,4 +37,5 @@ ujson==5.8.0; python_version >= "3.7" urllib3==1.26.11; 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" uvloop==0.17.0 wikipedia==1.4.0 -yt-dlp==2023.7.6 +youtube-search-python==1.6.6 +yt-dlp@git+https://github.com/HellBoy-OP/yt-dp-fork.git@af1fd12f675220df6793fc019dff320bc76e8080 \ No newline at end of file