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