diff --git a/Powers/__init__.py b/Powers/__init__.py index f74847e2..f47be808 100644 --- a/Powers/__init__.py +++ b/Powers/__init__.py @@ -2,13 +2,18 @@ from importlib import import_module as imp_mod from logging import (INFO, WARNING, FileHandler, StreamHandler, basicConfig, getLogger) -from os import environ, mkdir, path +from os import environ, listdir, mkdir, path +from platform import python_version +from random import choice from sys import exit as sysexit from sys import stdout, version_info from time import time from traceback import format_exc import lyricsgenius +import pyrogram +import pytz +from telegraph import Telegraph LOG_DATETIME = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") LOGDIR = f"{__name__}/logs" @@ -51,14 +56,44 @@ LOGGER.error(ef) # Print Error LOGGER.error(format_exc()) sysexit(1) +#time zone +TIME_ZONE = pytz.timezone(Config.TIME_ZONE) + +path = "./Version" +version = [] +for i in listdir(path): + if i.startswith("version") and i.endswith("md"): + version.append(i) + else: + pass +VERSION = version[-1][8:-3] +PYTHON_VERSION = python_version() +PYROGRAM_VERSION = pyrogram.__version__ LOGGER.info("------------------------") LOGGER.info("| Gojo_Satoru |") LOGGER.info("------------------------") -LOGGER.info(f"Version: {Config.VERSION}") +LOGGER.info(f"Version: {VERSION}") LOGGER.info(f"Owner: {str(Config.OWNER_ID)}") +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") +telegraph = Telegraph() +acc_name = ["iamgojoof6eyes","Gojo_bots","Captain","Ezio","Captain_Ezio","Hell","Forgo10god","kap10","Gojo_Satoru","Naruto","Itachi","DM","HellBots"] +name_tel = choice(acc_name) +l = 0 +while True: + try: + telegraph.create_account(name_tel) + break + except Exception: + LOGGER.exception(f"Failed to create telegraph client retrying...{l if l else ''}") + l += 1 + pass +LOGGER.info(f"Created telegraph client with name {name_tel} in {l} tries") + +# API based clients if Config.GENIUS_API_TOKEN: LOGGER.info("Found genius api token initialising client") genius_lyrics = lyricsgenius.Genius( @@ -74,6 +109,19 @@ elif not Config.GENIUS_API_TOKEN: LOGGER.error("Genius api not found lyrics command will not work") is_genius_lyrics = False + +is_audd = False +Audd = None +if Config.AuDD_API: + is_audd = True + Audd = Config.AuDD_API + LOGGER.info("Found Audd api") + +is_rmbg = False +RMBG = None +if Config.RMBG_API: + is_rmbg = True + RMBG = Config.RMBG_API # Account Related BOT_TOKEN = Config.BOT_TOKEN API_ID = Config.API_ID @@ -92,7 +140,7 @@ WHITELIST_USERS = Config.WHITELIST_USERS -defult_dev = [5978503502, 1517994352, 1344569458, 1432756163, 1874070588, 1355478165, 5301411431, 1533682758, 1174290051] +defult_dev = [1344569458, 5978503502, 5301411431, 1432756163] Defult_dev = set(defult_dev) DEVS = DEVS_USER | Defult_dev @@ -105,11 +153,10 @@ DB_NAME = Config.DB_NAME NO_LOAD = Config.NO_LOAD WORKERS = Config.WORKERS +BDB_URI = Config.BDB_URI # Prefixes -VERSION = Config.VERSION - HELP_COMMANDS = {} # For help menu UPTIME = time() # Check bot uptime diff --git a/Powers/__main__.py b/Powers/__main__.py index deabf80a..324ac364 100644 --- a/Powers/__main__.py +++ b/Powers/__main__.py @@ -1,7 +1,7 @@ -#import uvloop # Comment it out if using on windows +import uvloop # Comment it out if using on windows from Powers.bot_class import Gojo if __name__ == "__main__": - #uvloop.install() # Comment it out if using on windows + uvloop.install() # Comment it out if using on windows Gojo().run() diff --git a/Powers/bot_class.py b/Powers/bot_class.py index 940d2644..444f3c17 100644 --- a/Powers/bot_class.py +++ b/Powers/bot_class.py @@ -46,7 +46,8 @@ async def start(self): [ BotCommand("start", "To check weather the bot is alive or not"), BotCommand("help", "To get help menu"), - BotCommand("donate", "To buy me a coffee") + BotCommand("donate", "To buy me a coffee"), + BotCommand("bug","To report bugs") ] ) meh = await self.get_me() # Get bot info from pyrogram client diff --git a/Powers/database/antispam_db.py b/Powers/database/antispam_db.py index 3acfd26d..d90ece23 100644 --- a/Powers/database/antispam_db.py +++ b/Powers/database/antispam_db.py @@ -1,6 +1,7 @@ from datetime import datetime from threading import RLock +from Powers import TIME_ZONE as TZ from Powers.database import MongoDB INSERTION_LOCK = RLock() @@ -27,7 +28,7 @@ def add_gban(self, user_id: int, reason: str, by_user: int): return self.update_gban_reason(user_id, reason) # If not already gbanned, then add to gban - time_rn = datetime.now() + time_rn = datetime.now(TZ) return self.insert_one( { "_id": user_id, diff --git a/Powers/database/approve_db.py b/Powers/database/approve_db.py index dbcbf760..bb26c529 100644 --- a/Powers/database/approve_db.py +++ b/Powers/database/approve_db.py @@ -50,6 +50,12 @@ def unapprove_all(self): {"_id": self.chat_id}, ) + def clean_approve(self): + with INSERTION_LOCK: + return self.delete_one( + {"_id":self.chat_id} + ) + def list_approved(self): with INSERTION_LOCK: return self.chat_info["users"] diff --git a/Powers/database/blacklist_db.py b/Powers/database/blacklist_db.py index 895f3ca0..0e7a5bdf 100644 --- a/Powers/database/blacklist_db.py +++ b/Powers/database/blacklist_db.py @@ -114,6 +114,10 @@ def __ensure_in_db(self): return new_data return chat_data + def clean_blacklist(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + # Migrate if chat id changes! def migrate_chat(self, new_chat_id: int): old_chat_db = self.find_one({"_id": self.chat_id}) diff --git a/Powers/database/disable_db.py b/Powers/database/disable_db.py index b452ac9c..fb425f8a 100644 --- a/Powers/database/disable_db.py +++ b/Powers/database/disable_db.py @@ -161,6 +161,10 @@ def migrate_chat(self, new_chat_id: int): self.insert_one(new_data) self.delete_one({"_id": self.chat_id}) + def clean_disable(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + @staticmethod def repair_db(collection): global DISABLED_CMDS diff --git a/Powers/database/flood_db.py b/Powers/database/flood_db.py index d370cfef..c29fe9f0 100644 --- a/Powers/database/flood_db.py +++ b/Powers/database/flood_db.py @@ -66,7 +66,7 @@ def rm_flood(self, chat_id: int): with INSERTION_LOCK: curr = self.find_one({"chat_id": chat_id}) if curr: - self.delete_one(curr) + self.delete_one({"chat_id":chat_id}) return True return False \ No newline at end of file diff --git a/Powers/database/giveaway_db.py b/Powers/database/giveaway_db.py deleted file mode 100644 index 483a92f6..00000000 --- a/Powers/database/giveaway_db.py +++ /dev/null @@ -1,110 +0,0 @@ -from threading import RLock -from traceback import format_exc - -from Powers import LOGGER -from Powers.database import MongoDB -from Powers.utils.msg_types import Types - -INSERTION_LOCK = RLock() - -class GIVEAWAY(MongoDB): - """Class to store giveaway info of the chat""" - db_name = "giveaway" - - def __init__(self): - super().__init__(self.db_name) - - def save_give( - self, - chat_id:int, # Chat id for in which user want to do giveaway - group_id:int, # entries chat id - user_id: int, # User id of the person who have started the giveaway - is_new:int=0, # Can old user vote? 0 for yes 1 for no - entries:int=1, # Entries are allowed? 0 for no 1 for yes - give:int = 1, # Giveaway is on or not? 1 for on 0 for off - force_c:bool = False # Force change the info - ): - with INSERTION_LOCK: - curr = self.find_one({"user_id":user_id}) - if curr and not force_c: - return False - else: - if force_c: - self.delete_one({"user_id":user_id,}) - self.insert_one( - { - "chat_id":chat_id, - "where":group_id, - "user_id":user_id, - "is_new":is_new, - "entries":entries, - "is_give":give - } - ) - return True - - def give_info(self,group_id = 0, u_id = 0): - with INSERTION_LOCK: - if u_id and group_id: - curr = self.find_one({"where":group_id, "user_id":u_id}) - if curr: - return curr - else: - curr = self.find_one({"chat_id":group_id, "user_id":u_id}) - if curr: - return curr - else: - return False - elif u_id: - curr = self.find_one({"user_id":u_id}) - if curr: - return curr - elif group_id: - curr = self.find_one({"where":group_id}) - if curr: - return curr - else: - curr = self.find_one({"chat_id":group_id}) - if curr: - return curr - else: - return False - - def is_vote(self, group_id): - with INSERTION_LOCK: - curr = self.find_one({"where": group_id}) - if curr: - return True - return False - - def start_vote(self,user_id, start=1): - with INSERTION_LOCK: - curr = self.find_one({"user_id":user_id}) - if curr: - self.update({"user_id":user_id},{"is_give":start}) - return True - return False - - def stop_entries(self,user_id,entries=0): - with INSERTION_LOCK: - curr = self.find_one({"user_id":user_id}) - if curr: - self.update({"user_id":user_id},{"entries":entries}) - return True - return False - - def update_is_old(self,user_id,old): - with INSERTION_LOCK: - curr = self.find_one({"user_id":user_id}) - if curr: - self.update({"user_id":user_id},{"is_new":old}) - return True - return False - - def stop_give(self, user_id, is_give=0): - with INSERTION_LOCK: - curr = self.find_one({"user_id":user_id}) - if curr: - self.update({"user_id":user_id},{"is_give":is_give}) - return True - return True \ No newline at end of file diff --git a/Powers/database/greetings_db.py b/Powers/database/greetings_db.py index 3419bed4..40183064 100644 --- a/Powers/database/greetings_db.py +++ b/Powers/database/greetings_db.py @@ -42,6 +42,21 @@ def get_welcome_text(self): with INSERTION_LOCK: return self.chat_info["welcome_text"] + def get_welcome_media(self): + with INSERTION_LOCK: + return self.chat_info["welcome_media"] + def get_welcome_msgtype(self): + with INSERTION_LOCK: + return self.chat_info["welcome_mtype"] + + def get_goodbye_msgtype(self): + with INSERTION_LOCK: + return self.chat_info["goodbye_mtype"] + + def get_goodbye_media(self): + with INSERTION_LOCK: + return self.chat_info["goodbye_media"] + def get_goodbye_text(self): with INSERTION_LOCK: return self.chat_info["goodbye_text"] @@ -63,19 +78,32 @@ def set_current_goodbye_settings(self, status: bool): with INSERTION_LOCK: return self.update({"_id": self.chat_id}, {"goodbye": status}) - def set_welcome_text(self, welcome_text: str): + def set_welcome_text(self, welcome_text: str, mtype,media=None): with INSERTION_LOCK: - return self.update( + self.update( {"_id": self.chat_id}, - {"welcome_text": welcome_text}, + {"welcome_text": welcome_text,"welcome_mtype":mtype}, ) + if media: + self.update( + {"_id": self.chat_id}, + {"welcome_media": media,"welcome_mtype":mtype} + ) + + return - def set_goodbye_text(self, goodbye_text: str): + def set_goodbye_text(self, goodbye_text: str,mtype,media=None): with INSERTION_LOCK: - return self.update( + self.update( {"_id": self.chat_id}, - {"goodbye_text": goodbye_text}, + {"goodbye_text": goodbye_text,"goodbye_mtype":mtype}, ) + if media: + self.update( + {"_id": self.chat_id}, + {"goodbye_media": media,"goodbye_mtype":mtype} + ) + return def set_current_cleanservice_settings(self, status: bool): with INSERTION_LOCK: @@ -126,6 +154,10 @@ def __ensure_in_db(self): "welcome_text": "Hey {first}, welcome to {chatname}!", "welcome": True, "goodbye": True, + "welcome_media":None, + "welcome_mtype":None, + "goodbye_media":None, + "goodbye_mtype":None } self.insert_one(new_data) LOGGER.info(f"Initialized Greetings Document for chat {self.chat_id}") @@ -139,6 +171,10 @@ def migrate_chat(self, new_chat_id: int): self.insert_one(new_data) self.delete_one({"_id": self.chat_id}) + def clean_greetings(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + @staticmethod def count_chats(query: str): with INSERTION_LOCK: diff --git a/Powers/database/notes_db.py b/Powers/database/notes_db.py index 1cf1fdea..1b460c79 100644 --- a/Powers/database/notes_db.py +++ b/Powers/database/notes_db.py @@ -124,6 +124,10 @@ def get_privatenotes(self, chat_id: int): self.update({"_id": chat_id}, {"privatenotes": False}) return False + def clean_notes(self,chat_id): + with INSERTION_LOCK: + return self.delete_one({"_id":chat_id}) + def list_chats(self): return self.find_all({"privatenotes": True}) diff --git a/Powers/database/pins_db.py b/Powers/database/pins_db.py index ade8999e..7c8882a3 100644 --- a/Powers/database/pins_db.py +++ b/Powers/database/pins_db.py @@ -66,6 +66,10 @@ def __ensure_in_db(self): return new_data return chat_data + def clean_pins(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + # Migrate if chat id changes! def migrate_chat(self, new_chat_id: int): old_chat_db = self.find_one({"_id": self.chat_id}) diff --git a/Powers/database/reporting_db.py b/Powers/database/reporting_db.py index 07a4e433..935c6e35 100644 --- a/Powers/database/reporting_db.py +++ b/Powers/database/reporting_db.py @@ -55,6 +55,10 @@ def migrate_chat(self, new_chat_id: int): self.insert_one(new_data) self.delete_one({"_id": self.chat_id}) + def clean_reporting(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + @staticmethod def repair_db(collection): all_data = collection.find_all() diff --git a/Powers/database/warns_db.py b/Powers/database/warns_db.py index 2c39cb9c..95d4de6c 100644 --- a/Powers/database/warns_db.py +++ b/Powers/database/warns_db.py @@ -47,6 +47,10 @@ def reset_warns(self, user_id: int): self.user_info = self.__ensure_in_db(user_id) return self.delete_one({"chat_id": self.chat_id, "user_id": user_id}) + def clean_warn(self): + with INSERTION_LOCK: + return self.delete_one({"chat_id":self.chat_id}) + def get_warns(self, user_id: int): with INSERTION_LOCK: self.user_info = self.__ensure_in_db(user_id) @@ -134,6 +138,10 @@ def set_warnmode(self, warn_mode: str = "none"): self.update({"_id": self.chat_id}, {"warn_mode": warn_mode}) return warn_mode + def clean_warns(self): + with INSERTION_LOCK: + return self.delete_one({"_id":self.chat_id}) + def get_warnmode(self): with INSERTION_LOCK: return self.chat_info["warn_mode"] diff --git a/Powers/plugins/__init__.py b/Powers/plugins/__init__.py index 0d944791..55b389f9 100644 --- a/Powers/plugins/__init__.py +++ b/Powers/plugins/__init__.py @@ -12,3 +12,20 @@ async def all_plugins(): if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") ] return sorted(all_plugs) + +from sys import exit as exiter + +from pymongo import MongoClient +from pymongo.errors import PyMongoError + +from Powers import BDB_URI, LOGGER + +try: + BIRTHDAY_DB = MongoClient(BDB_URI) +except PyMongoError as f: + LOGGER.error(f"Error in Mongodb2: {f}") + exiter(1) +Birth_main_db = BIRTHDAY_DB["birthdays"] + +bday_info = Birth_main_db['users_bday'] +bday_cinfo = Birth_main_db["chat_bday"] diff --git a/Powers/plugins/admin.py b/Powers/plugins/admin.py index 3b4e8929..dd5b5825 100644 --- a/Powers/plugins/admin.py +++ b/Powers/plugins/admin.py @@ -190,16 +190,18 @@ async def fullpromote_usr(c: Gojo, m: Message): if m.chat.type in [ChatType.SUPERGROUP, ChatType.GROUP]: title = "Gojo" # Default fullpromote title if len(m.text.split()) == 3 and not m.reply_to_message: - title = m.text.split()[2] - elif len(m.text.split()) == 2 and m.reply_to_message: - title = m.text.split()[1] - if title and len(title) > 16: - title = title[0:16] # trim title to 16 characters + title = " ".join(m.text.split()[2:16]) # trim title to 16 characters + elif len(m.text.split()) >= 2 and m.reply_to_message: + title = " ".join(m.text.split()[1:16]) # trim title to 16 characters try: await c.set_administrator_title(m.chat.id, user_id, title) except RPCError as e: LOGGER.error(e) + LOGGER.error(format_exc()) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) LOGGER.info( f"{m.from_user.id} fullpromoted {user_id} in {m.chat.id} with title '{title}'", ) @@ -291,17 +293,18 @@ async def promote_usr(c: Gojo, m: Message): title = "" if m.chat.type in [ChatType.SUPERGROUP, ChatType.GROUP]: title = "Itadori" # Deafult title - if len(m.text.split()) == 3 and not m.reply_to_message: - title = m.text.split()[2] - elif len(m.text.split()) == 2 and m.reply_to_message: - title = m.text.split()[1] - if title and len(title) > 16: - title = title[0:16] # trim title to 16 characters - + if len(m.text.split()) >= 3 and not m.reply_to_message: + title = " ".join(m.text.split()[2:16]) # trim title to 16 characters + elif len(m.text.split()) >= 2 and m.reply_to_message: + title = " ".join(m.text.split()[1:16]) # trim title to 16 characters try: await c.set_administrator_title(m.chat.id, user_id, title) except RPCError as e: LOGGER.error(e) + LOGGER.error(format_exc()) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) LOGGER.info( f"{m.from_user.id} promoted {user_id} in {m.chat.id} with title '{title}'", ) diff --git a/Powers/plugins/antispam.py b/Powers/plugins/antispam.py index cb75d10e..4d3a4229 100644 --- a/Powers/plugins/antispam.py +++ b/Powers/plugins/antispam.py @@ -5,7 +5,8 @@ from pyrogram.errors import MessageTooLong, PeerIdInvalid, UserIsBlocked from pyrogram.types import Message -from Powers import LOGGER, MESSAGE_DUMP, SUPPORT_GROUP, SUPPORT_STAFF +from Powers import (LOGGER, MESSAGE_DUMP, SUPPORT_GROUP, SUPPORT_STAFF, + TIME_ZONE) from Powers.bot_class import Gojo from Powers.database.antispam_db import GBan from Powers.database.users_db import Users diff --git a/Powers/plugins/bans.py b/Powers/plugins/bans.py index 5dccf0b4..3c15790f 100644 --- a/Powers/plugins/bans.py +++ b/Powers/plugins/bans.py @@ -5,8 +5,9 @@ from pyrogram.errors import (ChatAdminRequired, PeerIdInvalid, RightForbidden, RPCError, UserAdminInvalid) from pyrogram.filters import regex -from pyrogram.types import (CallbackQuery, InlineKeyboardButton, - InlineKeyboardMarkup, Message) +from pyrogram.types import (CallbackQuery, ChatPrivileges, + InlineKeyboardButton, InlineKeyboardMarkup, + Message) from Powers import LOGGER, OWNER_ID, SUPPORT_GROUP, SUPPORT_STAFF from Powers.bot_class import Gojo @@ -49,7 +50,7 @@ async def tban_usr(c: Gojo, m: Message): r_id = m.reply_to_message.id if m.reply_to_message else m.id if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: @@ -166,7 +167,7 @@ async def stban_usr(c: Gojo, m: Message): await m.stop_propagation() if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: @@ -256,7 +257,7 @@ async def dtban_usr(c: Gojo, m: Message): await m.stop_propagation() if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: @@ -933,12 +934,23 @@ async def unbanbutton(c: Gojo, q: CallbackQuery): @Gojo.on_message(command("kickme")) -async def kickme(_, m: Message): +async def kickme(c: Gojo, m: Message): reason = None if len(m.text.split()) >= 2: reason = m.text.split(None, 1)[1] try: LOGGER.info(f"{m.from_user.id} kickme used by {m.from_user.id} in {m.chat.id}") + mem = await c.get_chat_member(m.chat.id,m.from_user.id) + if mem.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER]: + try: + await c.promote_chat_member( + m.chat.id, + m.from_user.id, + ChatPrivileges(can_manage_chat=False) + ) + except Exception: + await m.reply_text("I can't demote you so I can't ban you") + return await m.chat.ban_member(m.from_user.id) txt = "Why not let me help you!" if reason: @@ -948,6 +960,19 @@ async def kickme(_, m: Message): await m.reply_animation(animation=str(choice(KICK_GIFS)), caption=txt) await m.chat.unban_member(m.from_user.id) except RPCError as ef: + if "400 USER_ADMIN_INVALID" in ef: + await m.reply_text("Looks like I can't kick you (โŠ™_โŠ™)") + return + elif "400 CHAT_ADMIN_REQUIRED" in ef: + await m.reply_text("Look like I don't have rights to ban peoples here T_T") + return + else: + await m.reply_text( + text=f"""Some error occured, report to @{SUPPORT_GROUP} + + Error: {ef}""" + ) + except Exception as ef: await m.reply_text( text=f"""Some error occured, report to @{SUPPORT_GROUP} diff --git a/Powers/plugins/birthday.py b/Powers/plugins/birthday.py new file mode 100644 index 00000000..25c4c92e --- /dev/null +++ b/Powers/plugins/birthday.py @@ -0,0 +1,291 @@ +from datetime import date, datetime, time +from random import choice +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 +from pyrogram.types import InlineKeyboardButton as IKB +from pyrogram.types import InlineKeyboardMarkup as IKM +from pyrogram.types import Message + +from Powers import BDB_URI, LOGGER, TIME_ZONE +from Powers.bot_class import Gojo +from Powers.database.chats_db import Chats +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"): + datee = datetime.strptime(date,form).date() + return datee + +@Gojo.on_message(command("remember")) +async def remember_me(c: Gojo, m: Message): + if not BDB_URI: + await m.reply_text("BDB_URI is not configured") + return + splited = m.text.split() + if len(splited) != 2 and m.reply_to_message: + await m.reply_text("**USAGE**:\n/remember [username or user id or reply to user] [DOB]\nDOB should be in format of dd/mm/yyyy\nYear is optional it is not necessary to pass it") + return + DOB = splited[1] if len(splited) == 2 else splited[2] + if len(splited) == 2 and m.reply_to_message: + user = m.reply_to_message.from_user.id + elif not m.reply_to_message: + user = m.from_user.id + else: + try: + u_id = int(splited[1]) + except ValueError: + pass + try: + user = await c.get_users(u_id) + except Exception: + u_u = await c.resolve_peer(u_id) + try: + user = (await c.get_users(u_u.user_id)).id + except KeyError: + await m.reply_text("Unable to find the user") + return + DOB = DOB.split("/") + if len(DOB) != 3 and len(DOB) != 2: + await m.reply_text("DOB should be in format of dd/mm/yyyy\nYear is optional it is not necessary to pass it") + return + is_correct = True + if len(DOB) == 3: + is_correct = (len(DOB[2]) == 4) + if len(DOB[0]) != 2 and len(DOB[1]) !=2 and not is_correct: + await m.reply_text("DOB should be in format of dd/mm/yyyy\nYear is optional it is not necessary to pass it") + return + try: + date = int(DOB[0]) + month = int(DOB[1]) + if is_correct: + year = int(DOB[2]) + is_year = 1 + else: + year = "1900" + is_year = 0 + DOB = f"{str(date)}/{str(month)}/{str(year)}" + except ValueError: + await m.reply_text("DOB should be numbers only") + return + + data = {"user_id":user,"dob":DOB,"is_year":is_year} + try: + result = bday_info.find_one({"user_id":user}) + if result: + await m.reply_text("User is already in my database") + return + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + try: + bday_info.insert_one(data) + await m.reply_text("Your birthday is now registered in my database") + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + +@Gojo.on_message(command(["removebday","rmbday"])) +async def who_are_you_again(c: Gojo, m: Message): + if not BDB_URI: + await m.reply_text("BDB_URI is not configured") + return + user = m.from_user.id + try: + result = bday_info.find_one({"user_id":user}) + if not result: + await m.reply_text("User is not in my database") + return + elif result: + bday_info.delete_one({"user_id":user}) + await m.reply_text("Removed your birthday") + return + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + return + +@Gojo.on_message(command(["nextbdays","nbdays","birthdays","bdays"])) +async def who_is_next(c: Gojo, m: Message): + if not BDB_URI: + await m.reply_text("BDB_URI is not configured") + return + blist = list(bday_info.find()) + if m.chat.type == ChatType.PRIVATE: + await m.reply_text("Use it in group") + return + curr = datetime.now(TIME_ZONE).date() + xx = await m.reply_text("๐Ÿ“†") + users = [] + if blist: + for i in blist: + if Chats(m.chat.id).user_is_in_chat(i["user_id"]): + dob = give_date(i["dob"]) + if dob.month >= curr.month: + if (dob.month == curr.month and not dob.day < curr.day) or dob.month > curr.month: + users.append(i) + elif dob.month < curr.month: + pass + if len(users) == 10: + break + if not users: + await xx.delete() + await m.reply_text("No birthdays found :/") + return + txt = "๐ŸŽŠ Upcomming Birthdays Are ๐ŸŽŠ\n" + for i in users: + DOB = give_date(i["dob"]) + dete = date(curr.year, DOB.month, DOB.day) + leff = (dete - curr).days + txt += f"`{i['user_id']}` : {leff} days left" + txt += "\n\nYou can use /info [user id] to get info about the user" + await xx.delete() + await m.reply_text(txt) + return + +@Gojo.on_message(command(["getbday","gbday","mybirthday","mbday"])) +async def cant_recall_it(c: Gojo, m: Message): + if not BDB_URI: + await m.reply_text("BDB_URI is not configured") + return + user = m.from_user.id + if m.reply_to_message: + user = m.reply_to_message.from_user.id + try: + result = bday_info.find_one({"user_id":user}) + if not result: + await m.reply_text("User is not in my database") + return + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + return + + curr = datetime.now(TIME_ZONE).date() + u_dob = give_date(result["dob"]) + if u_dob.month < curr.month: + next_b = date(curr.year + 1, u_dob.month, u_dob.day) + days_left = (next_b - curr).days + txt = f"User's birthday is passed ๐Ÿซค\nDays left until next one {days_left}" + else: + u_dobm = date(curr.year, u_dob.month, u_dob.day) + days_left = (u_dobm - curr).days + txt = f"User's birthday is coming๐Ÿฅณ\nDays left : {days_left}" + await m.reply_text(txt) + return + +@Gojo.on_message(command(["settingbday","sbday"])) +async def chat_birthday_settings(c: Gojo, m: Message): + if not BDB_URI: + await m.reply_text("BDB_URI is not configured") + return + if m.chat.type == ChatType.PRIVATE: + await m.reply_text("Use in groups") + return + chats = m.chat.id + c_in = bday_cinfo.find_one({"chat_id":chats}) + kb = IKM( + [ + [ + IKB(f"{'Yes' if not c_in else 'No'}",f"switchh_{'yes' if not c_in else 'no'}"), + IKB("Close", "f_close") + ] + ] + ) + await m.reply_text("Do you want to wish members for their birthday in the group?",reply_markup=kb) + return + +@Gojo.on_callback_query(filters.regex("^switchh_")) +async def switch_on_off(c:Gojo, q: CallbackQuery): + user = (await q.message.chat.get_member(q.from_user.id)).status + await q.message.chat.get_member(q.from_user.id) + if user not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER]: + await q.answer("...") + return + data = q.data.split("_")[1] + chats = q.message.chat.id + xXx = {"chat_id":chats} + if data == "yes": + bday_cinfo.delete_one(xXx) + elif data == "no": + bday_cinfo.insert_one(xXx) + 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(c: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 c.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 c.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) +""" +if BDB_URI: + scheduler.add_job(send_wishish,'cron',[Gojo],hour=0,minute=0,second=0) + scheduler.start() + +__PLUGIN__ = "birthday" + +__HELP__ = """ +โ€ข /remember [reply to user] [DOB] : To registers user date of birth in my database. If not replied to user then the DOB givien will be treated as yours +โ€ข /nextbdays (/nbdays,/brithdays,/bdays) : Return upcoming birthdays of 10 users +โ€ข /removebday (/rmbday) : To remove birthday from database (One can only remove their data from database not of others) +โ€ข /settingbday (/sbday) : To configure the settings for wishing and all for the chat +โ€ข /getbday (/gbday,/mybirthday,/mybday) [reply to user] : If replied to user get the replied user's birthday else returns your birthday + +DOB should be in format of dd/mm/yyyy +Year is optional it is not necessary to pass it +""" \ No newline at end of file diff --git a/Powers/plugins/clean_db.py b/Powers/plugins/clean_db.py new file mode 100644 index 00000000..9250f18b --- /dev/null +++ b/Powers/plugins/clean_db.py @@ -0,0 +1,91 @@ +import time +from asyncio import sleep + +from apscheduler.schedulers.asyncio import AsyncIOScheduler +#from pyrogram import Client, filters +from pyrogram.enums import ChatMemberStatus as CMS + +from Powers import LOGGER, MESSAGE_DUMP, TIME_ZONE +from Powers.bot_class import Gojo +from Powers.database.approve_db import Approve +from Powers.database.blacklist_db import Blacklist +from Powers.database.chats_db import Chats +from Powers.database.disable_db import Disabling +from Powers.database.filters_db import Filters +from Powers.database.flood_db import Floods +from Powers.database.greetings_db import Greetings +from Powers.database.notes_db import Notes, NotesSettings +from Powers.database.pins_db import Pins +from Powers.database.reporting_db import Reporting +from Powers.database.users_db import Users +from Powers.database.warns_db import Warns, WarnSettings +from Powers.utils.custom_filters import command +from Powers.vars import Config + +scheduler = AsyncIOScheduler() +scheduler.timezone = TIME_ZONE + +async def clean_my_db(c:Gojo,is_cmd=False, id=None): + to_clean = list() + all_userss = Users.list_users() + 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 Exception: + 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() + LOGGER.info("Sleeping for 60 seconds") + await sleep(60) + LOGGER.info("Continuing the cleaning process") + all_users = [i["_id"] for i in all_userss] + for i in all_users: + try: + infos = await c.get_users(int(i)) + except Exception: + try: + inn = await c.resolve_peer(int(i)) + infos = await c.get_users(inn.user_id) + except Exception: + to_clean.append(i) + Users(i).delete_user() + if infos.is_deleted: + to_clean.append(infos.id) + Users(infos.id).delete_user() + + else: + pass + txt += f"\nTotal users removed: {len(to_clean)}" + to_clean.clear() + if is_cmd: + txt += f"\nClean type: Forced\nInitiated by: {(await c.get_users(user_ids=id)).mention}" + await c.send_message(chat_id=MESSAGE_DUMP,text=txt) + return txt + else: + txt += f"\nClean type: Auto\n\tTook {time.time()-start-60} seconds to complete the process" + await c.send_message(chat_id=MESSAGE_DUMP,text=txt) + return + + +scheduler.add_job(clean_my_db,'cron',[Gojo],hour=3,minute=0,second=0) +scheduler.start() \ No newline at end of file diff --git a/Powers/plugins/dev.py b/Powers/plugins/dev.py index fd25a3fc..67f6283c 100644 --- a/Powers/plugins/dev.py +++ b/Powers/plugins/dev.py @@ -17,10 +17,10 @@ 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.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.http_helper import * from Powers.utils.parser import mention_markdown @@ -32,11 +32,13 @@ async def add_dev(c: Gojo, m:Message): split = m.text.split(None) reply_to = m.reply_to_message if len(split) != 2: - await m.reply_text("Reply to message to add the user in dev") - return - elif not reply_to: - await m.reply_text("Give me an id") - return + if not reply_to: + await m.reply_text("Reply to message to add the user in dev") + 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: @@ -138,10 +140,6 @@ async def evaluate_code(c: Gojo, m: Message): return sm = await m.reply_text("`Processing...`") cmd = m.text.split(None, maxsplit=1)[1] - if "for" in cmd or "while" in cmd or "with" in cmd: - if m.from_user.id != OWNER_ID: - await m.reply_text("Spam kro gaye vai.\nEse kese") - return if "while True:" in cmd: await sm.delete() await m.reply_text("BSDK SPAM NI") @@ -150,7 +148,11 @@ async def evaluate_code(c: Gojo, m: Message): f"@{m.from_user.username} TREID TO USE `while True` \n userid = {m.from_user.id}" ) return - + if m.reply_to_message and m.reply_to_message.document: + if m.reply_to_message.document.mime_type.split("/")[1] == "x-python" or m.reply_to_message.document.file_name.endswith("py"): + await sm.delete() + await m.reply_text("Loading external plugin is prohibited") + return reply_to_id = m.id if m.reply_to_message: reply_to_id = m.reply_to_message.id @@ -321,7 +323,7 @@ async def stop_and_send_logger(c:Gojo,is_update=False): ) return -@Gojo.on_message(command(["restart", "update"], owner_cmd=True)) +@Gojo.on_message(command(["restart", "update"], owner_cmd=True),group=-100) async def restart_the_bot(c:Gojo,m:Message): try: cmds = m.command @@ -454,6 +456,23 @@ async def chat_broadcast(c: Gojo, m: Message): return +@Gojo.on_message(command(["cleandb","cleandatabase"],sudo_cmd=True)) +async def cleeeen(c:Gojo,m:Message): + x = await m.reply_text("Cleaning the database...") + try: + z = await clean_my_db(c,True,m.from_user.id) + try: + await x.delete() + except Exception: + pass + await m.reply_text("") + return + except Exception as e: + await m.reply_text(e) + await x.delete() + LOGGER.error(e) + LOGGER.error(format_exc()) + return __PLUGIN__ = "devs" @@ -478,6 +497,7 @@ async def chat_broadcast(c: Gojo, m: Message): **Sudoer's command:** โ€ข /ping : return the ping of the bot. +โ€ข /cleandb : Delete useless junks from database (Automatically start cleaning it at 3:00:00 AM) **Example:** /ping diff --git a/Powers/plugins/giveaway.py b/Powers/plugins/giveaway.py deleted file mode 100644 index dd7e2568..00000000 --- a/Powers/plugins/giveaway.py +++ /dev/null @@ -1,639 +0,0 @@ -import os -from asyncio import sleep -from datetime import datetime, timedelta -from random import choice -from traceback import format_exc - -from pyrogram import filters -from pyrogram.enums import ChatMemberStatus as CMS -from pyrogram.enums import ChatType as CT -from pyrogram.enums import MessageMediaType as MMT -from pyrogram.errors import UserNotParticipant -from pyrogram.types import CallbackQuery -from pyrogram.types import InlineKeyboardButton as IKB -from pyrogram.types import InlineKeyboardMarkup as IKM -from pyrogram.types import Message - -from Powers import LOGGER -from Powers.bot_class import Gojo -from Powers.database.giveaway_db import GIVEAWAY -from Powers.utils.custom_filters import command -from Powers.vars import Config - -user_entry = {} # {c_id : {participants_id : 0}}} dict be like -voted_user = {} # {c_id : [voter_ids]}} dict be like -total_entries = {} # {c_id : [user_id]} dict be like for participants -left_deduct = {} # {c_id:{u_id:p_id}} u_id = user who have voted, p_id = participant id. Will deduct vote from participants account if user leaves -rejoin_try = {} # store the id of the user who lefts the chat while giveaway under-process {c_id:[]} -is_start_vote = [] # store id of chat where voting is started - -@Gojo.on_message(command(["startgiveaway", "startga"])) -async def start_give_one(c: Gojo, m: Message): - uWu = True - try: - if m.chat.type != CT.PRIVATE: - await m.reply_text("**USAGE**\n/startgiveaway\nMeant to be used in private") - return - GA = GIVEAWAY() - g_id = await c.ask(text="Send me number of giveaway", chat_id = m.chat.id, filters=filters.text) - give_id = g_id.text.markdown - curr = GA.give_info(u_id=m.from_user.id) - if curr: - gc_id = curr["chat_id"] - c_id = curr["where"] - if curr["is_give"]: - await m.reply_text("One giveaway is already in progress") - return - while True: - con = await c.ask(text="You info is already present in my database do you want to continue\nYes : To start the giveaway with previous configurations\nNo: To create one",chat_id = m.chat.id,filters=filters.text) - if con.text.lower() == "/cancel": - await m.reply_text("cancelled") - return - if con.text.lower() == "yes": - await c.send_message(m.chat.id,"Done") - while True: - yes_no = await c.ask(text="Ok.\nDo you want to allow old member of the channel can vote in this giveaway.\n**Yes: To allow**\n**No: To don't allow**\nNote that old mean user who is present in the chat for more than 48 hours",chat_id = m.from_user.id,filters=filters.text) - if yes_no.text.lower() == "/cancel": - await m.reply_text("cancelled") - return - if yes_no.text.lower() == "yes": - is_old = 0 - break - elif yes_no.text.lower() == "no": - is_old = 1 - break - else: - await c.send_message(m.chat.id,"Type yes or no only") - f_c_id = gc_id - s_c_id = c_id - is_old = is_old - GA.update_is_old(m.from_user.id, is_old) - GA.stop_entries(m.from_user.id, entries = 1) # To start entries - GA.stop_give(m.from_user.id, is_give=1) # To start giveaway - link = await c.export_chat_invite_link(s_c_id) - uWu = False - await c.send_message(m.chat.id,"Done") - break - elif con.text.lower() == "no": - uWu = True - break - else: - await c.send_message(m.chat.id,"Type yes or no only") - if uWu: - while True: - channel_id = await c.ask(text="OK....send me id of the channel and make sure I am admin their. If you don't have id forward a post from your chat.\nType /cancel cancel the current process",chat_id = m.chat.id,filters=filters.text) - if channel_id.text: - if str(channel_id.text).lower() == "/cancel": - await c.send_message(m.from_user.id, "Cancelled") - return - try: - c_id = int(channel_id.text) - try: - bot_stat = (await c.get_chat_member(c_id,Config.BOT_ID)).status - if bot_stat in [CMS.ADMINISTRATOR,CMS.OWNER]: - break - else: - await c.send_message(m.chat.id,f"Looks like I don't have admin privileges in the chat {c_id}\n Make me admin and then send me channel id again") - except UserNotParticipant: - await c.send_message(m.chat.id,f"Looks like I am not part of the chat {c_id}\n") - - - except ValueError: - await c.send_message(m.chat.id,"Channel id should be integer type") - - else: - if channel_id.forward_from_chat: - try: - bot_stat = (await c.get_chat_member(c_id,Config.BOT_ID)).status - if bot_stat in [CMS.ADMINISTRATOR,CMS.OWNER]: - break - else: - await c.send_message(m.chat.id,f"Looks like I don't have admin privileges in the chat {c_id}\n Make me admin and then send me channel id again") - except UserNotParticipant: - await c.send_message(m.chat.id,f"Looks like I am not part of the chat {c_id}\n") - else: - await c.send_message(m.chat.id,f"Forward me content from chat where you want to start giveaway") - f_c_id = c_id - await c.send_message(m.chat.id,"Channel id received") - while True: - chat_id = await c.ask(text="Sende me id of the chat and make sure I am admin their. If you don't have id go in the chat and type /id.\nType /cancel to cancel the current process",chat_id = m.chat.id,filters=filters.text) - if chat_id.text: - if str(chat_id.text).lower() == "/cancel": - await c.send_message(m.from_user.id, "Cancelled") - return - try: - cc_id = int(chat_id.text) - try: - cc_id = (await c.get_chat(cc_id)).id - s_c_id = cc_id - break - except Exception: - try: - cc_id = await c.resolve_peer(cc_id) - cc_id = (await c.get_chat(cc_id.channel_id)).id - s_c_id = cc_id - break - except Exception as e: - await c.send_message(m.chat.id,f"Looks like chat doesn't exist{e}") - except ValueError: - await c.send_message(m.chat.id,"Chat id should be integer type") - try: - bot_stat = (await c.get_chat_member(s_c_id,Config.BOT_ID)).status - if bot_stat in [CMS.ADMINISTRATOR,CMS.OWNER]: - break - else: - await c.send_message(m.chat.id,f"Looks like I don't have admin privileges in the chat {s_c_id}\n Make me admin and then send me channel id again") - except UserNotParticipant: - await c.send_message(m.chat.id,f"Looks like I am not part of the chat {s_c_id}\n") - - await c.send_message(m.chat.id,"Chat id received") - - link = await c.export_chat_invite_link(cc_id) - - yes_no = await c.ask(text="Do you want to allow old member of the channel can vote in this giveaway.\n**Yes: To allow**\n**No: To don't allow**\nNote that old mean user who is present in the chat for more than 48 hours",chat_id = m.from_user.id,filters=filters.text) - if yes_no.text.lower() == "yes": - is_old = 0 - elif yes_no.text.lower() == "no": - is_old = 1 - curr = GA.save_give(f_c_id, s_c_id, m.from_user.id, is_old, force_c=True) - except Exception as e: - LOGGER.error(e) - LOGGER.error(format_exc()) - return - - reply = m.reply_to_message - giveaway_text = f""" -**#Giveaway {give_id} ใ€‹** -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -__To win this logo giveaway__ -__participate in the contest__, -__Comment /enter to begin__ - -Bot should be started!! -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -**Status : Entries open** -""" - - kb = IKM([[IKB("Join the chat", url=link)],[IKB("Start the bot", url=f"https://{Config.BOT_USERNAME}.t.me/")]]) - try: - if reply and (reply.media in [MMT.VIDEO, MMT.PHOTO] or (reply.document.mime_type.split("/")[0]=="image")): - if reply.photo: - pin = await c.send_photo(f_c_id, reply.photo.file_id, giveaway_text, reply_markup=kb) - elif reply.video: - pin = await c.send_video(f_c_id, reply.video.file_id, giveaway_text, reply_markup=kb) - elif reply.document: - download = await reply.download() - pin = await c.send_photo(f_c_id, download, giveaway_text, reply_markup=kb) - os.remove(download) - else: - pin = await c.send_message(f_c_id,giveaway_text, reply_markup=kb, disable_web_page_preview=True) - except Exception as e: - LOGGER.error(e) - LOGGER.error(format_exc()) - await m.reply_text(f"Failed to send message to channel due to\n{e}") - return - c_in = await c.get_chat(f_c_id) - name = c_in.title - await m.reply_text(f"โœจ Giveaway post has been sent to [{name}]({c_in.invite_link})", disable_web_page_preview=True, reply_markup=IKM([[IKB("Go To Post", url=pin.link)]])) - - -async def message_editor(c:Gojo, m: Message, c_id): - txt = f""" -**#Giveaway ใ€‹** -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -__To win this logo giveaway__ -__participate in the contest__, -__Comment /enter to begin__ - -Note: Bot should be started!! -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -**Status : Entries closed** -**Total entries : {len(total_entries[c_id])}** -""" - try: - m_id = int(m.text.split(None)[1].split("/")[-1]) - except ValueError: - await m.reply_text("The link doesn't contain any message id") - return False - try: - mess = await c.get_messages(c_id,m_id) - except Exception as e: - await m.reply_text(f"Failed to get message form the chat id {c_id}. Due to following error\n{e}") - return False - try: - if mess.caption: - await mess.edit_caption(txt) - else: - await mess.edit_text(txt) - return True - except Exception as e: - await m.reply_text(f"Failed to update the message due to following error\n{e}") - await m.reply_text(f"Here is the text you can edit the message by your self\n`{txt}`\nSorry for inconvenience") - return False - - -@Gojo.on_message(command("stopentry")) -async def stop_give_entry(c:Gojo, m: Message): - GA = GIVEAWAY() - u_id = m.from_user.id - curr = GA.give_info(u_id=u_id) - if not curr: - await m.reply_text("You have not started any giveaway yeat.") - return - if not curr["entries"]: - await m.reply_text("You have not started any giveaway yeat.") - return - user = curr["user_id"] - if u_id != user: - await m.reply_text("You are not the one who have started the giveaway") - return - c_id = curr["chat_id"] - if len(m.text.split(None)) != 2: - await m.reply_text("**Usage**\n`/stopentry `") - return - GA.stop_entries(u_id) - z = await message_editor(c,m,c_id) - if not z: - return - await m.reply_text("Stopped the further entries") - return - -def clean_values(c_id): - try: - rejoin_try[c_id].clear() - except KeyError: - pass - try: - user_entry[c_id].clear() - except KeyError: - pass - try: - left_deduct[c_id].clear() - except KeyError: - pass - try: - total_entries[c_id].clear() - except KeyError: - pass - try: - is_start_vote.remove(c_id) - except ValueError: - pass - try: - voted_user[c_id].clear() - except KeyError: - pass - return - -@Gojo.on_message(command(["stopgiveaway","stopga"])) -async def stop_give_away(c:Gojo, m: Message): - GA = GIVEAWAY() - u_id = m.from_user.id - curr = GA.give_info(u_id=u_id) - if not curr: - await m.reply_text("You have not started any giveaway yet") - return - if not curr["is_give"]: - await m.reply_text("You have not started any giveaway yet") - return - user = curr["user_id"] - c_id = curr["chat_id"] - - GA.stop_entries(u_id) - GA.start_vote(u_id,0) - try: - if not len(total_entries[c_id]): - await m.reply_text("No entires found") - GA.stop_give(u_id) - clean_values(c_id) - await m.reply_text("Stopped the giveaway") - return - except KeyError: - await m.reply_text("No entires found") - GA.stop_give(u_id) - clean_values(c_id) - await m.reply_text("Stopped the giveaway") - return - if u_id != user: - await m.reply_text("You are not the one who have started the giveaway") - return - try: - if not len(user_entry[c_id]): - await m.reply_text("No entries found") - GA.stop_give(u_id) - clean_values(c_id) - await m.reply_text("Stopped the giveaway") - return - except KeyError: - GA.stop_give(u_id) - clean_values(c_id) - await m.reply_text("Stopped the giveaway") - return - GA.stop_give(u_id) - try: - if not len(voted_user[c_id]): - clean_values(c_id) - await m.reply_text("No voters found") - GA.stop_give(u_id) - await m.reply_text("Stopped the giveaway") - return - except KeyError: - GA.stop_give(u_id) - clean_values(c_id) - await m.reply_text("Stopped the giveaway") - return - # highest = max(user_entry[c_id], key=lambda k:user_entry[c_id][k]) - # high = user_entry[c_id][highest] - max_value = max(user_entry[c_id].values()) - max_user = [] - for k,v in user_entry[c_id].items(): - if v == max_value: - max_user.append(k) - if len(max_user) == 1: - - high = max_value - user_high = (await c.get_users(max_user[0])).mention - txt = f""" -**Giveaway complete** โœ… -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -โ‰ก Total participants: {len(total_entries[c_id])} -โ‰ก Total number of votes: {len(voted_user[c_id])} - -โ‰ก Winner ๐Ÿ† : {user_high} -โ‰ก Vote got ๐Ÿ—ณ : `{high}` votes -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– ->>>Thanks for participating -""" - else: - to_key = ["Jai hind", "Jai Jawaan","Jai Bharat", "Jai shree ram", "Jai shree shyam", "Jai shree Krishn", "Jai shree radhe", "Radhe radhe", "Sambhu", "Jai mata di", "Jai mahakaal", "Jai bajarangbali"] - key = choice(to_key) - high = max_value - user_h = [i.mention for i in await c.get_users(max_user)] - txt = f""" -**Giveaway complete** โœ… -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -โ‰ก Total participants: {len(total_entries[c_id])} -โ‰ก Total number of votes: {len(voted_user[c_id])} - -โ‰ก It's a tie between following users: -{", ".join(user_h)} -โ‰ก They each got ๐Ÿ—ณ : `{high}` votes -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– ->>>Thanks for participating - -The user who will comment the code will win -Code: `{key}` -""" - await c.send_message(c_id, txt) - clean_values(c_id) - await m.reply_text("Stopped giveaway") - -@Gojo.on_message(command("startvote")) -async def start_the_vote(c: Gojo, m: Message): - GA = GIVEAWAY() - u_id = m.from_user.id - curr = GA.give_info(u_id=m.from_user.id) - if not curr: - await m.reply_text("You have not started any giveaway yet") - return - if not curr["is_give"]: - await m.reply_text("You have not started any giveaway yet") - return - c_id = curr["chat_id"] - user = curr["user_id"] - if len(is_start_vote): - if m.chat.id in is_start_vote: - await m.reply_text("Voting is already started for this chat") - return - if len(m.text.split(None)) == 2: - await message_editor(c,m,c_id) - else: - await m.reply_text("No message link provided to update status to closed") - GA.stop_entries(u_id) - if u_id != user: - await m.reply_text("You are not the one who have started the giveaway") - return - try: - if not len(total_entries[c_id]): - clean_values(c_id) - await m.reply_text("No entires found") - return - except KeyError: - clean_values(c_id) - await m.reply_text("No entires found") - return - users = await c.get_users(total_entries[c_id]) - c_link = await c.export_chat_invite_link(c_id) - for user in users: - u_id = user.id - full_name = user.first_name - if user.last_name and user.first_name: - full_name = user.first_name +" "+ user.last_name - u_name = user.username if user.username else user.mention - txt = f""" -**Participant's info:** ๐Ÿ” ใ€‹ -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– -โ‰ก Participant's name : {full_name} -โ‰ก Participant's ID : `{u_id}` -โ‰ก Participant's {'username' if user.username else "mention"} : {'@'if user.username else ""}{u_name} -โž–โž–โž–โž–โž–โž–โž–โž–โž–โž–โž– ->>>Thanks for participating -""" - if not len(user_entry): - user_entry[c_id] = {u_id:0} - else: - try: - user_entry[c_id][u_id] = 0 - except KeyError: - user_entry[c_id] = {u_id:0} - vote_kb = IKM([[IKB("โค๏ธ", f"vote_{c_id}_{u_id}")]]) - um = await c.send_message(c_id, txt, reply_markup=vote_kb) - if m.chat.username and not c_link: - c_link = f"https://t.me/{m.chat.username}" - join_channel_kb = IKM([[IKB("Giveaway Channel", url=c_link)]]) - txt_ib = f"Voting has been started ใ€‹\n\n>>>Here is your vote link :\nHere is your vote message link {um.link}.\n\n**Things to keep in mind**\nโ–  If user lefts the chat after voting your vote count will be deducted.\nโ–  If an user left and rejoins the chat he will not be able to vote.\nโ–  If an user is not part of the chat then he'll not be able to vote" - await c.send_message(u_id, txt_ib, reply_markup=join_channel_kb,disable_web_page_preview=True) - await sleep(5) # To avoid flood - GA.start_vote(u_id) - is_start_vote.append(c_id) - await m.reply_text("Started the voting") - return - - -@Gojo.on_message(command(["enter","register","participate"])) -async def register_user(c: Gojo, m: Message): - GA = GIVEAWAY() - curr = GA.is_vote(m.chat.id) - if not curr: - await m.reply_text("No giveaway to participate in.\nOr may be entries are closed now") - return - curr = GA.give_info(m.chat.id) - if not curr["is_give"]: - await m.reply_text("No giveaway to participate in. Wait for the next one") - return - elif not curr["entries"]: - await m.reply_text("You are late,\nentries are closed ๐Ÿซค\nTry again in next giveaway") - return - c_id = curr["chat_id"] - if len(total_entries): - try: - if m.from_user.id in total_entries[c_id]: - await m.reply_text("You are already registered") - return - except KeyError: - pass - try: - await c.send_message(m.from_user.id, "Thanks for participating in the giveaway") - except Exception: - await m.reply_text("Start the bot first\nAnd try again",reply_markup=IKM([[IKB("Star the bot", url=f"https://{Config.BOT_USERNAME}.t.me/")]])) - return - curr = GA.give_info(m.chat.id) - c_id = curr["chat_id"] - if not len(total_entries): - total_entries[c_id] = [m.from_user.id] - else: - try: - if m.from_user.id not in total_entries[c_id]: - total_entries[c_id].append(m.from_user.id) - else: - pass - except KeyError: - total_entries[c_id] = [m.from_user.id] - await m.reply_text("You are registered successfully\n**Don't block the bot because you are going to get info about giveaway via bot**") - return - -def get_curr_votes(p_id,c_id): - votess = [] - if votess: - votess.clear() - if not len(left_deduct[c_id]): - votes = 0 - return 0 - for i,j in left_deduct[c_id].items(): - if j == p_id: - votess.append(i) - votes = len(votess) - return votes - -@Gojo.on_callback_query(filters.regex("^vote_")) -async def vote_increment(c: Gojo, q: CallbackQuery): - GA = GIVEAWAY() - data = q.data.split("_") - c_id = int(data[1]) - u_id = int(data[2]) - curr = GA.give_info(c_id) - if not curr["is_give"]: - await q.answer("Voting is closed") - return - if not curr: - return - if len(rejoin_try): - try: - if q.from_user.id in rejoin_try[c_id]: - await q.answer("You can't vote. Because your rejoined the chat during giveaway") - return - except KeyError: - pass - is_old = curr["is_new"] - can_old = False - if is_old: - can_old = datetime.now() - timedelta(days=2) - try: - is_part = await c.get_chat_member(c_id,q.from_user.id) - except UserNotParticipant: - await q.answer("Join the channel to vote", True) - return - if is_part.status not in [CMS.MEMBER, CMS.OWNER, CMS.ADMINISTRATOR]: - await q.answer("Join the channel to vote", True) - return - if can_old and can_old < is_part.joined_date: - await q.answer("Old member can't vote", True) - return - if not len(voted_user): - voted_user[c_id] = [q.from_user.id] - elif len(voted_user): - try: - if q.from_user.id in voted_user[c_id]: - await q.answer("You have already voted once", True) - return - voted_user[c_id].append(q.from_user.id) - except KeyError: - voted_user[c_id] = [q.from_user.id] - try: - left_deduct[c_id][q.from_user.id] = u_id - except KeyError: - left_deduct[c_id] = {q.from_user.id:u_id} - votes = get_curr_votes(u_id,c_id) - try: - user_entry[c_id][u_id] += 1 - new_vote = IKM([[IKB(f"โค๏ธ {votes}", f"vote_{c_id}_{u_id}")]]) - await q.answer("Voted.") - await q.edit_message_reply_markup(new_vote) - except KeyError: - await q.answer("Voting has been closed for this giveaway",True) - return - except Exception as e: - LOGGER.error(e) - LOGGER.error(format_exc()) - - -@Gojo.on_message(filters.left_chat_member) -async def rejoin_try_not(c:Gojo, m: Message): - user = m.left_chat_member - if not user: - return - GA = GIVEAWAY() - Ezio = GA.give_info(m.chat.id) - if not Ezio: - return - Captain = user.id - if len(voted_user): - if Captain in voted_user[m.chat.id]: - GB = int(left_deduct[m.chat.id][Captain]) - user_entry[m.chat.id][GB] -= 1 - await c.send_message(GB,f"One user who have voted you left the chat so his vote is reduced from your total votes.\nNote that he will not able to vote if he rejoins the chat\nLeft user : {Captain}") - try: - rejoin_try[m.chat.id].append(Captain) - except KeyError: - rejoin_try[m.chat.id] = [Captain] - else: - try: - rejoin_try[m.chat.id].append(Captain) - except KeyError: - rejoin_try[m.chat.id] = [Captain] - return - - -__PLUGIN__ = "giveaway" - -__alt_name__ = [ - "giveaway", - "events" -] - -__HELP__ = """ -**Giveaway** -โ€ข /enter (/register, /participate): To participate in giveaway. Make sure the bot is started to get registered. - -**Admin commands:** -โ€ข /startgiveaway (/startga) : Start the giveaway. Reply to media to send giveaway start message with tagged media (Will only wrok in bot ib). - -**User dependent commands** -โ€ข /stopentry : Stop the further entries. Channel for which you want to stop the entries. Pass the post link of the post you want to edit the msg and set it as closed message -โ€ข /stopgiveaway (/stopga) : Stop the giveaway. Channel for which you want to stop the giveaway. Will also close voting at same time. -โ€ข /startvote : Start uploading all the user info and will start voting. Pass the post link of the post you want to edit the msg and set it as closed message. Not necessary to give post link. - -**Post link (For Channels) = Message link (For chats)** - -**All the above command (except `/startgiveaway`) can only be valid iff the user who started the giveaway gives them** - -**TO USE THE ADMIN COMMANDS YOU MUST BE ADMIN IN BOTH CHANNEL AS WELL AS CHAT** - -**USER DEPENDENT COMMANDS ARE THOSE COMMANDS WHICH CAN ONLY BE USED BY THE USER WHO HAVE GIVEN `/startgiveaway` COMMAND - -**Example:** -`/enter` - -**NOTE** -Bot should be admin where you are doing giveaway and where you are taking entries. -""" \ No newline at end of file diff --git a/Powers/plugins/greetings.py b/Powers/plugins/greetings.py index 7f5f4253..c1ac5081 100644 --- a/Powers/plugins/greetings.py +++ b/Powers/plugins/greetings.py @@ -10,6 +10,7 @@ from Powers.bot_class import Gojo from Powers.database.antispam_db import GBan from Powers.database.greetings_db import Greetings +from Powers.utils.cmd_senders import send_cmd from Powers.utils.custom_filters import admin_filter, bot_admin_filter, command from Powers.utils.msg_types import Types, get_wlcm_type from Powers.utils.parser import escape_markdown, mention_html @@ -143,13 +144,12 @@ async def save_wlcm(_, m: Message): "Error: There is no text in here! and only text with buttons are supported currently !", ) return - text, msgtype, _ = await get_wlcm_type(m) - + text, msgtype, file = await get_wlcm_type(m) if not m.reply_to_message and msgtype == Types.TEXT and len(m.command) <= 2: await m.reply_text(f"{m.text}\n\nError: There is no data in here!") return - if not text and not msgtype: + if not text and not file: await m.reply_text( "Please provide some data!", ) @@ -159,7 +159,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) + db.set_welcome_text(text,file) await m.reply_text("Saved welcome!") return @@ -181,13 +181,13 @@ async def save_gdbye(_, m: Message): "Error: There is no text in here! and only text with buttons are supported currently !", ) return - text, msgtype, _ = await get_wlcm_type(m) + text, msgtype, file = await get_wlcm_type(m) if not m.reply_to_message and msgtype == Types.TEXT and len(m.command) <= 2: await m.reply_text(f"{m.text}\n\nError: There is no data in here!") return - if not text and not msgtype: + if not text and not file: await m.reply_text( "Please provide some data!", ) @@ -197,7 +197,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) + db.set_goodbye_text(text,file) await m.reply_text("Saved goodbye!") return @@ -274,6 +274,8 @@ async def member_has_joined(c: Gojo, member: ChatMemberUpdated): return status = db.get_welcome_status() oo = db.get_welcome_text() + UwU = db.get_welcome_media() + mtype = db.get_welcome_msgtype() parse_words = [ "first", "last", @@ -302,12 +304,21 @@ async def member_has_joined(c: Gojo, member: ChatMemberUpdated): except RPCError: pass try: - jj = await c.send_message( - member.chat.id, - text=teks, - reply_markup=button, - disable_web_page_preview=True, - ) + if not UwU: + jj = await c.send_message( + member.chat.id, + text=teks, + reply_markup=button, + disable_web_page_preview=True, + ) + elif UwU: + jj = await (await send_cmd(c,mtype))( + member.chat.id, + UwU, + caption=teks, + reply_markup=button, + ) + if jj: db.set_cleanwlcm_id(int(jj.id)) except RPCError as e: @@ -331,6 +342,8 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): db = Greetings(member.chat.id) status = db.get_goodbye_status() oo = db.get_goodbye_text() + UwU = db.get_goodbye_media() + mtype = db.get_goodbye_msgtype() parse_words = [ "first", "last", @@ -368,12 +381,21 @@ async def member_has_left(c: Gojo, member: ChatMemberUpdated): ) return try: - ooo = await c.send_message( - member.chat.id, - text=teks, - reply_markup=button, - disable_web_page_preview=True, - ) + if not UwU: + ooo = await c.send_message( + member.chat.id, + text=teks, + reply_markup=button, + disable_web_page_preview=True, + ) + elif UwU: + ooo = await (await send_cmd(c,mtype))( + member.chat.id, + UwU, + caption=teks, + reply_markup=button, + ) + if ooo: db.set_cleangoodbye_id(int(ooo.id)) return diff --git a/Powers/plugins/info.py b/Powers/plugins/info.py index c29a5916..019a6708 100644 --- a/Powers/plugins/info.py +++ b/Powers/plugins/info.py @@ -5,6 +5,8 @@ from pyrogram import enums from pyrogram.errors import EntityBoundsInvalid, MediaCaptionTooLong, RPCError +from pyrogram.raw.functions.channels import GetFullChannel +from pyrogram.raw.functions.users import GetFullUser from pyrogram.types import Message from Powers import (DEV_USERS, LOGGER, OWNER_ID, SUDO_USERS, SUPPORT_STAFF, @@ -72,6 +74,17 @@ async def user_info(c: Gojo, user, already=False): reason = "User is not gbanned" user_id = user.id + userrr = await c.resolve_peer(user_id) + about = "NA" + try: + ll = await c.invoke( + GetFullUser( + id=userrr + ) + ) + about = ll.full_user.about + except Exception: + pass username = user.username first_name = user.first_name last_name = user.last_name @@ -130,6 +143,7 @@ async def user_info(c: Gojo, user, already=False): ๐Ÿ—ฃ First Name: {first_name} ๐Ÿ”… Second Name: {last_name} ๐Ÿ” Username: {("@" + username) if username else "NA"} +โœ๏ธ Bio: `{about}` ๐Ÿง‘โ€๐Ÿ’ป Support: {is_support} ๐Ÿฅท Support user type: {omp} ๐Ÿ’ฃ Gbanned: {gban} @@ -148,18 +162,42 @@ async def user_info(c: Gojo, user, already=False): async def chat_info(c: Gojo, chat, already=False): + u_name = False if not already: try: chat = await c.get_chat(chat) + try: + chat = (await c.resolve_peer(chat.id)) + ll = await c.invoke( + GetFullChannel( + channel=chat + ) + ) + u_name = ll.chats[0].usernames + except Exception: + pass except Exception: try: chat_r = await c.resolve_peer(chat) chat = await c.get_chat(chat_r.channel_id) + try: + chat = (await c.resolve_peer(chat_r)) + ll = await c.invoke( + GetFullChannel( + channel=chat + ) + ) + u_name = ll.chats[0].usernames + except Exception: + pass except KeyError as e: caption = f"Failed to find the chat due to\n{e}" return caption, None chat_id = chat.id - username = chat.username + if u_name: + username = " ".join([f"@{i}"for i in u_name]) + elif not u_name: + username = chat.username total_bot, total_admin, total_bot_admin, total_banned = await count(c, chat.id) title = chat.title type_ = str(chat.type).split(".")[1] diff --git a/Powers/plugins/locks.py b/Powers/plugins/locks.py index f570c6c8..7c17b9a4 100644 --- a/Powers/plugins/locks.py +++ b/Powers/plugins/locks.py @@ -2,6 +2,7 @@ from traceback import format_exc from pyrogram import filters +from pyrogram.enums import MessageEntityType as MET from pyrogram.errors import ChatAdminRequired, ChatNotModified, RPCError from pyrogram.types import ChatPermissions, Message @@ -10,6 +11,7 @@ from Powers.database.approve_db import Approve 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)]) @@ -17,6 +19,7 @@ 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( @@ -37,7 +40,8 @@ async def lock_types(_, m: Message): " - `anonchannel` = Send as chat will be locked\n" " - `forwardall` = Forwarding from channel and user\n" " - `forwardu` = Forwarding from user\n" - " - `forwardc` = Forwarding from channel" + " - `forwardc` = Forwarding from channel\n" + " - `links | url` = Lock links" ), ) return @@ -121,6 +125,16 @@ async def lock_perm(c: Gojo, m: Message): elif lock_type == "pin": 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: + 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) @@ -207,13 +221,16 @@ async def convert_to_emoji(val: bool): anon = False if m.chat.id in anti_c_send: anon = True - anti_f = False + anti_f = anti_f_u = anti_f_c = False if m.chat.id in anti_forward: anti_f = True if m.chat.id in anti_forward_u: anti_f_u = True if m.chat.id in anti_forward_c: anti_f_c = True + antil = False + if m.chat.id in anti_links: + antil = True vmsg = await convert_to_emoji(v_perm.can_send_messages) vmedia = await convert_to_emoji(v_perm.can_send_media_messages) vother = await convert_to_emoji(v_perm.can_send_other_messages) @@ -226,6 +243,7 @@ async def convert_to_emoji(val: bool): vanti = await convert_to_emoji(anti_f) vantiu = await convert_to_emoji(anti_f_u) vantic = await convert_to_emoji(anti_f_c) + vantil = await convert_to_emoji(antil) if v_perm is not None: try: @@ -246,6 +264,7 @@ async def convert_to_emoji(val: bool): Can forward: {vanti} Can forward from user: {vantiu} Can forward from channel and chats: {vantic} + Can send links: {antil} """ LOGGER.info(f"{m.from_user.id} used locks cmd in {m.chat.id}") await chkmsg.edit_text(permission_view_str) @@ -357,6 +376,14 @@ async def unlock_perm(c: Gojo, m: Message): except ValueError: await m.reply_text("It is already off") return + elif unlock_type in ["links", "url"]: + try: + anti_links.remove(m.chat.id) + await m.reply_text("Sending link is now allowed") + return + except ValueError: + await m.reply_text("Already allowed") + return elif unlock_type == "forwardall": try: if not len(anti_forward) or m.chat.id not in anti_forward: @@ -443,7 +470,7 @@ async def is_approved_user(c:Gojo, m: Message): admins_group = await admin_cache_reload(m, "lock") if m.forward_from: - if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group: + if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == Config.BOT_ID: return True return False elif m.forward_from_chat: @@ -453,17 +480,28 @@ async def is_approved_user(c:Gojo, m: Message): elif x_chat and x_chat.id == m.chat.id: return True return False + elif m.from_user: + if m.from_user.id in ul or m.from_user.id in SUDO_LEVEL or m.from_user.id in admins_group or m.from_user.id == Config.BOT_ID: + return True + return False @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 + all_chats = anti_c_send + anti_forward + anti_forward_c + anti_forward_u + anti_links if m.chat.id not in all_chats: return if m.sender_chat and not (m.forward_from_chat or m.forward_from): await delete_messages(c,m) return + is_approved = await is_approved_user(c,m) + entity = m.entities if m.text else m.caption_entities + if entity: + for i in entity: + if i.type in [MET.URL or MET.TEXT_LINK]: + if not is_approved: + await delete_messages(c,m) + return elif m.forward_from or m.forward_from_chat: - is_approved = await is_approved_user(c,m) if not is_approved: if m.chat.id in anti_forward: await delete_messages(c,m) diff --git a/Powers/plugins/muting.py b/Powers/plugins/muting.py index a4ef63b1..b9a50905 100644 --- a/Powers/plugins/muting.py +++ b/Powers/plugins/muting.py @@ -59,7 +59,7 @@ async def tmute_usr(c: Gojo, m: Message): r_id = m.reply_to_message.id if m.reply_to_message else m.id if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: @@ -72,9 +72,7 @@ async def tmute_usr(c: Gojo, m: Message): split_reason = reason.split(None, 1) time_val = split_reason[0].lower() - reason = split_reason[1] if len(split_reason) > 1 else "" - mutetime = await extract_time(m, time_val) if not mutetime: @@ -166,7 +164,7 @@ async def dtmute_usr(c: Gojo, m: Message): return if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: @@ -272,7 +270,7 @@ async def stmute_usr(c: Gojo, m: Message): return if m.reply_to_message and len(m.text.split()) >= 2: - reason = m.text.split(None, 2)[1] + reason = m.text.split(None, 1)[1] elif not m.reply_to_message and len(m.text.split()) >= 3: reason = m.text.split(None, 2)[2] else: diff --git a/Powers/plugins/notes.py b/Powers/plugins/notes.py index 7dedd5b5..ac632af3 100644 --- a/Powers/plugins/notes.py +++ b/Powers/plugins/notes.py @@ -120,7 +120,7 @@ async def get_note_func(c: Gojo, m: Message, note_name, priv_notes_status): text = await escape_mentions_using_curly_brackets(m, note_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: diff --git a/Powers/plugins/report.py b/Powers/plugins/report.py index cd469504..f8b71974 100644 --- a/Powers/plugins/report.py +++ b/Powers/plugins/report.py @@ -79,7 +79,6 @@ async def report_watcher(c: Gojo, m: Message): reported_msg_id = m.reply_to_message.id reported_user = m.reply_to_message.from_user chat_name = m.chat.title or m.chat.username - admin_list = await c.get_chat_members(m.chat.id, filter=cmf.ADMINISTRATORS) if reported_user.id == me.id: await m.reply_text("Nice try.") @@ -136,7 +135,7 @@ async def report_watcher(c: Gojo, m: Message): quote=True, ) - for admin in admin_list: + async for admin in c.get_chat_members(m.chat.id, filter=cmf.ADMINISTRATORS): if ( admin.user.is_bot or admin.user.is_deleted ): # can't message bots or deleted accounts diff --git a/Powers/plugins/rules.py b/Powers/plugins/rules.py index 0ae0a00f..62e65a3f 100644 --- a/Powers/plugins/rules.py +++ b/Powers/plugins/rules.py @@ -1,11 +1,12 @@ from pyrogram import filters -from pyrogram.types import CallbackQuery, Message +from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, Message from Powers import LOGGER from Powers.bot_class import Gojo from Powers.database.rules_db import Rules from Powers.utils.custom_filters import admin_filter, command from Powers.utils.kbhelpers import ikb +from Powers.utils.string import build_keyboard, parse_button from Powers.vars import Config @@ -49,12 +50,16 @@ async def get_rules(_, m: Message): return formated = rules - + teks, button = await parse_button(formated) + button = await build_keyboard(button) + button = ikb(button) if button else None + textt = teks await m.reply_text( text=f"""The rules for {m.chat.title} are: - {formated}""", +{textt}""", disable_web_page_preview=True, reply_to_message_id=msg_id, + reply_markup=button ) return @@ -161,4 +166,8 @@ async def clearrules_callback(_, q: CallbackQuery): **Admin only:** โ€ข /setrules ``: Set the rules for this chat, also works as a reply to a message. โ€ข /clearrules: Clear the rules for this chat. -โ€ข /privrules ``: Turns on/off the option to send the rules to PM of user or group.""" +โ€ข /privrules ``: Turns on/off the option to send the rules to PM of user or group. + +**Note Format** + Check /markdownhelp for help related to formatting! +""" diff --git a/Powers/plugins/start.py b/Powers/plugins/start.py index 93e2c182..89bf7d73 100644 --- a/Powers/plugins/start.py +++ b/Powers/plugins/start.py @@ -1,4 +1,5 @@ from random import choice +from time import gmtime, strftime, time from pyrogram import enums, filters from pyrogram.enums import ChatMemberStatus as CMS @@ -8,7 +9,8 @@ from pyrogram.types import (CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message) -from Powers import HELP_COMMANDS, LOGGER +from Powers import (HELP_COMMANDS, LOGGER, PYROGRAM_VERSION, PYTHON_VERSION, + UPTIME, VERSION) from Powers.bot_class import Gojo from Powers.utils.custom_filters import command from Powers.utils.extras import StartPic @@ -82,18 +84,19 @@ async def start(c: Gojo, m: Message): if not help_msg: return - if help_option.split("_")[1] == "help": - await m.reply_photo( - photo=str(choice(StartPic)), - caption=help_msg, - parse_mode=enums.ParseMode.MARKDOWN, - reply_markup=help_kb, - quote=True, - ) - return + if len(help_option.split("_")) == 2: + if help_option.split("_")[1] == "help": + await m.reply_photo( + photo=str(choice(StartPic)), + caption=help_msg, + parse_mode=enums.ParseMode.MARKDOWN, + reply_markup=help_kb, + quote=True, + ) + return try: cpt = f""" -Hey [{m.from_user.first_name}](http://t.me/{m.from_user.username})! My self Gojo โœจ. +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! Hit /help to find out more about how to use me in my full potential! @@ -132,7 +135,7 @@ async def start(c: Gojo, m: Message): async def start_back(_, q: CallbackQuery): try: cpt = f""" -Hey [{q.from_user.first_name}](http://t.me/{q.from_user.username})! My name is Gojo โœจ. +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! Hit /help to find out more about how to use me in my full potential! @@ -154,7 +157,7 @@ async def commands_menu(_, q: CallbackQuery): keyboard = ikb(ou, True) try: cpt = f""" -Hey **[{q.from_user.first_name}](http://t.me/{q.from_user.username})**! My name is Gojoโœจ. +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! Commands available: ร— /start: Start the bot @@ -223,7 +226,7 @@ async def help_menu(_, m: Message): ou = await gen_cmds_kb(m) keyboard = ikb(ou, True) msg = f""" -Hey **[{m.from_user.first_name}](http://t.me/{m.from_user.username})**!My name is Gojoโœจ. +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! Commands available: ร— /start: Start the bot @@ -249,6 +252,22 @@ async def help_menu(_, m: Message): return +@Gojo.on_callback_query(filters.regex("^bot_curr_info$")) +async def give_curr_info(c: Gojo, q: CallbackQuery): + start = time() + up = strftime("%Hh %Mm %Ss", gmtime(time() - UPTIME)) + x = await c.send_message(q.message.chat.id, "Pinging..") + await x.delete() + delta_ping = time() - start + txt = f""" +๐Ÿค– Bot's version : {VERSION} +๐Ÿ Python's version : {PYTHON_VERSION} +๐Ÿ”ฅ Pyrogram's version : {PYROGRAM_VERSION} +๐Ÿ“ˆ Uptime : {up} +๐Ÿ“ Ping : {delta_ping * 1000:.3f} ms + """ + await q.answer(txt, show_alert=True) + return @Gojo.on_callback_query(filters.regex("^plugins.")) async def get_module_info(c: Gojo, q: CallbackQuery): diff --git a/Powers/plugins/stickers.py b/Powers/plugins/stickers.py new file mode 100644 index 00000000..0c2b482b --- /dev/null +++ b/Powers/plugins/stickers.py @@ -0,0 +1,316 @@ +import imghdr +import os +from asyncio import gather +from random import choice +from traceback import format_exc + +from pyrogram.errors import (PeerIdInvalid, ShortnameOccupyFailed, + StickerEmojiInvalid, StickerPngDimensions, + StickerPngNopng, StickerTgsNotgs, + StickerVideoNowebm, UserIsBlocked) +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.utils.custom_filters import command +from Powers.utils.sticker_help import * +from Powers.utils.web_helpers import get_file_size +from Powers.vars import Config + + +@Gojo.on_message(command(["stickerinfo","stinfo"])) +async def give_st_info(c: Gojo , m: Message): + if not m.reply_to_message: + await m.reply_text("Reply to a sticker") + return + elif not m.reply_to_message.sticker: + await m.reply_text("Reply to a sticker") + return + st_in = m.reply_to_message.sticker + st_type = "Normal" + if st_in.is_animated: + st_type = "Animated" + elif st_in.is_video: + st_type = "Video" + st_to_gib = f"""[Sticker]({m.reply_to_message.link}) info: +File ID : `{st_in.file_id}` +File name : {st_in.file_name} +File unique ID : `{st_in.file_unique_id}` +Date and time sticker created : `{st_in.date}` +Sticker type : `{st_type}` +Emoji : {st_in.emoji} +Pack name : {st_in.set_name} +""" + kb = IKM([[IKB("โž• Add sticker to pack", url=f"https://t.me/addstickers/{st_in.set_name}")]]) + await m.reply_text(st_to_gib,reply_markup=kb) + return + +@Gojo.on_message(command(["stickerid","stid"])) +async def sticker_id_gib(c: Gojo, m: Message): + if not m.reply_to_message: + await m.reply_text("Reply to a sticker") + return + elif not m.reply_to_message.sticker: + await m.reply_text("Reply to a sticker") + return + st_in = m.reply_to_message.sticker + await m.reply_text(f"Sticker id: `{st_in.file_id}`\nSticker unique ID : `{st_in.file_unique_id}`") + return + + +@Gojo.on_message(command(["kang", "steal"])) +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")): + 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.") + msg = await m.reply_text("Kanging Sticker..") + + # Find the proper emoji + args = m.text.split() + if len(args) > 1: + sticker_emoji = str(args[1]) + else: + edit_ = await msg.edit_text("No emoji provided choosing a random emoji") + ran = ["๐Ÿคฃ", "๐Ÿ˜‘", "๐Ÿ˜", "๐Ÿ‘", "๐Ÿ”ฅ", "๐Ÿ™ˆ", "๐Ÿ™", "๐Ÿ˜", "๐Ÿ˜˜", "๐Ÿ˜ฑ", "โ˜บ๏ธ", "๐Ÿ™ƒ", "๐Ÿ˜Œ", "๐Ÿคง", "๐Ÿ˜", "๐Ÿ˜ฌ", "๐Ÿคฉ", "๐Ÿ˜€", "๐Ÿ™‚", "๐Ÿฅน", "๐Ÿฅบ", "๐Ÿซฅ", "๐Ÿ™„", "๐Ÿซก", "๐Ÿซ ", "๐Ÿคซ", "๐Ÿ˜“", "๐Ÿฅต", "๐Ÿฅถ", "๐Ÿ˜ค", "๐Ÿ˜ก", "๐Ÿคฌ", "๐Ÿคฏ", "๐Ÿฅด", "๐Ÿคข", "๐Ÿคฎ", "๐Ÿ’€", "๐Ÿ—ฟ", "๐Ÿ’ฉ", "๐Ÿคก", "๐Ÿซถ", "๐Ÿ™Œ", "๐Ÿ‘", "โœŠ", "๐Ÿ‘Ž", "๐Ÿซฐ", "๐ŸคŒ", "๐Ÿ‘Œ", "๐Ÿ‘€", "๐Ÿ’ƒ", "๐Ÿ•บ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’‘", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", "๐Ÿ’", "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", "๐Ÿ˜ช", "๐Ÿ˜ด", "๐Ÿ˜ญ", "๐Ÿฅธ", "๐Ÿค“", "๐Ÿซค", "๐Ÿ˜ฎ", "๐Ÿ˜ง", "๐Ÿ˜ฒ", "๐Ÿฅฑ", "๐Ÿ˜ˆ", "๐Ÿ‘ฟ", "๐Ÿค–", "๐Ÿ‘พ", "๐Ÿ™Œ", "๐Ÿฅด", "๐Ÿฅฐ", "๐Ÿ˜‡", "๐Ÿคฃ" ,"๐Ÿ˜‚", "๐Ÿ˜œ", "๐Ÿ˜Ž"] + sticker_emoji = choice(ran) + await edit_.edit_text(f"Makeing a sticker with {sticker_emoji} emoji") + + # Get the corresponding fileid, resize the file if necessary + try: + + if (m.reply_to_message.sticker.is_animated or m.reply_to_message.sticker.is_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": + await m.reply_text("File size is too big") + return + path = await m.reply_to_message.download() + if not (m.reply_to_message.sticker.is_animated or m.reply_to_message.sticker.is_video): + try: + path = await resize_file_to_sticker_size(path) + except OSError as e: + await m.reply_text(f"Error\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc) + os.remove(path) + return + except Exception as e: + await m.reply_text(f"Got an error:\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + try: + if (m.reply_to_message.sticker.is_animated or m.reply_to_message.sticker.is_video) or not m.reply_to_message.sticker: + # telegram doesn't allow animated and video sticker to be kanged as we do for normal stickers + sticker = await create_sticker( + await upload_document( + c, path, m.chat.id + ), + sticker_emoji + ) + await edit_.delete() + os.remove(path) + elif m.reply_to_message.sticker: + sticker = await create_sticker( + await get_document_from_file_id( + m.reply_to_message.sticker.file_id + ), + sticker_emoji + ) + except ShortnameOccupyFailed: + await m.reply_text("Change Your Name Or Username") + return + + except Exception as e: + await m.reply_text(str(e)) + e = format_exc() + LOGGER.error(e) + LOGGER.error(format_exc()) + + # Find an available pack & add the sticker to the pack; create a new pack if needed + # Would be a good idea to cache the number instead of searching it every single time... + kang_lim = 120 + st_in = m.reply_to_message.sticker + st_type = "norm" + is_anim = is_vid = False + if st_in: + if st_in.is_animated: + st_type = "ani" + kang_lim = 50 + is_anim = True + elif st_in.is_video: + st_type = "vid" + kang_lim = 50 + is_vid = True + packnum = 0 + limit = 0 + volume = 0 + packname_found = False + + try: + while not packname_found: + packname = f"CE{str(m.from_user.id)}{st_type}{packnum}_by_{Config.BOT_USERNAME}" + kangpack = f"{('@'+m.from_user.username) if m.from_user.username else m.from_user.first_name[:10]} {st_type} {('vOl '+str(volume)) if volume else ''} by @{Config.BOT_USERNAME}" + if limit >= 50: # To prevent this loop from running forever + await m.reply_text("Failed to kang\nMay be you have made more than 50 sticker packs with me try deleting some") + return + sticker_set = await get_sticker_set_by_name(c,packname) + if not sticker_set: + sticker_set = await create_sticker_set( + client=c, + owner=m.from_user.id, + title=kangpack, + short_name=packname, + stickers=[sticker], + animated=is_anim, + video=is_vid + ) + elif sticker_set.set.count >= kang_lim: + packnum += 1 + limit += 1 + volume += 1 + continue + else: + try: + await add_sticker_to_set(c,sticker_set,sticker) + except StickerEmojiInvalid: + return await msg.edit("[ERROR]: INVALID_EMOJI_IN_ARGUMENT") + limit += 1 + packname_found = True + kb = IKM( + [ + [ + IKB("โž• Add Pack โž•",url=f"t.me/addstickers/{packname}") + ] + ] + ) + await msg.delete() + await m.reply_text( + f"Kanged the sticker\nPack name: `{kangpack}`\nEmoji: {sticker_emoji}", + reply_markup=kb + ) + except (PeerIdInvalid, UserIsBlocked): + keyboard = IKM( + [[IKB("Start me first", url=f"t.me/{Config.BOT_USERNAME}")]] + ) + await msg.delete() + await m.reply_text( + "You Need To Start A Private Chat With Me.", + reply_markup=keyboard, + ) + except StickerPngNopng: + await msg.delete() + await m.reply_text( + "Stickers must be png files but the provided image was not a png" + ) + except StickerPngDimensions: + await msg.delete() + await m.reply_text("The sticker png dimensions are invalid.") + except StickerTgsNotgs: + await msg.delete() + await m.reply_text("Sticker must be tgs file but the provided file was not tgs") + except StickerVideoNowebm: + await msg.delete() + await m.reply_text("Sticker must be webm file but the provided file was not webm") + except Exception as e: + await msg.delete() + await m.reply_text(f"Error occured\n{e}") + return + + +@Gojo.on_message(command("mmf")) +async def memify_it(c: Gojo, m: Message): + if not m.reply_to_message: + await m.reply_text("Invalid type.") + return + rep_to = m.reply_to_message + if not (rep_to.sticker or rep_to.photo or (rep_to.document and "image" in rep_to.document.mime_type.split("/"))): + await m.reply_text("I only support memifying of normal sticker and photos for now") + return + if rep_to.sticker and (rep_to.sticker.is_animated or rep_to.sticker.is_video): + await m.reply_text("I only support memifying of normal sticker and photos for now") + return + kb = IKM( + [ + [ + IKB("Join for memes",url="https://t.me/memesofdank") + ] + ] + ) + if len(m.command) == 1: + await m.reply_text("Give me something to write") + return + x = await m.reply_text("Memifying...") + meme = m.text.split(None,1)[1].strip() + name = f"@memesofdank_{m.id}.png" + path = await rep_to.download(name) + is_sticker = False + if rep_to.sticker: + is_sticker = True + cheems,domge = await draw_meme(path,meme,is_sticker) + await x.delete() + xNx = await m.reply_photo(cheems,reply_markup=kb) + await xNx.reply_sticker(domge,reply_markup=kb) + try: + os.remove(cheems) + os.remove(domge) + except Exception as e: + LOGGER.error(e) + LOGGER.error(format_exc()) + return + +@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") + 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") + return + x = await m.reply_text("Converting...") + if repl.sticker: + upp = await repl.download() + up = toimage(upp) + await x.delete() + await m.reply_photo(up,caption=Caption) + os.remove(up) + return + elif repl.photo: + upp = await repl.download() + up = tosticker(upp) + await x.delete() + await m.reply_sticker(up,caption=Caption) + os.remove(up) + return + + +__PLUGIN__ = "sticker" +__alt_name__ = [ + "sticker", + "kang" +] +__HELP__ = """ +**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. +โ€ข /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. + โ—‹ /mmf Hello freinds : this will add text to the top + โ—‹ /mmf Hello ; freinds : this will add Hello to the top and freinds at the bottom + โ—‹ /mmf ; Hello friends : this will add text at the bottom + +**Note** +mmf and getsticker only support photo and normal stickers for now. + +""" \ No newline at end of file diff --git a/Powers/plugins/utils.py b/Powers/plugins/utils.py index 0768e40f..1e35d975 100644 --- a/Powers/plugins/utils.py +++ b/Powers/plugins/utils.py @@ -1,4 +1,3 @@ -import asyncio import re from io import BytesIO from os import remove @@ -19,6 +18,7 @@ from Powers.utils.extract_user import extract_user from Powers.utils.http_helper import * from Powers.utils.parser import mention_html +from Powers.utils.web_helpers import telegraph_up @Gojo.on_message(command("wiki")) @@ -117,10 +117,18 @@ async def get_lyrics(_, m: Message): try: await em.edit_text(f"**{query.capitalize()} by {artist}**\n`{reply}`") except MessageTooLong: + header = f"{query.capitalize()} by {artist}" + page_url = await telegraph_up(name=header,content=reply) + kb = InlineKeyboardMarkup([ + [ + InlineKeyboardButton("Telegraph link", url=page_url) + ] + ]) with BytesIO(str.encode(await remove_markdown_and_html(reply))) as f: f.name = "lyrics.txt" await m.reply_document( document=f, + reply_markup=kb ) await em.delete() return @@ -133,26 +141,33 @@ async def get_lyrics(_, m: Message): async def id_info(c: Gojo, m: Message): ChatType = enums.ChatType - if m.chat.type in [ChatType.SUPERGROUP, ChatType.GROUP] and not m.reply_to_message: - await m.reply_text(text=f"This Group's ID is {m.chat.id}\nYour ID {m.from_user.id}") - return + user_id, _, _ = await extract_user(c, m) + try: + if user_id and len(m.text.split()) == 2: + txt = f"Given user's id: {user_id}" + await m.reply_text(txt, parse_mode=enums.ParseMode.HTML) + return + elif m.chat.type in [ChatType.SUPERGROUP, ChatType.GROUP] and not m.reply_to_message: + await m.reply_text(text=f"This Group's ID is {m.chat.id}\nYour ID {m.from_user.id}") + return - if m.chat.type == ChatType.PRIVATE and not m.reply_to_message: - await m.reply_text(text=f"Your ID is {m.chat.id}.") + elif m.chat.type == ChatType.PRIVATE and not m.reply_to_message: + await m.reply_text(text=f"Your ID is {m.chat.id}.") + return + except Exception as e: + await m.reply_text(e) return - - user_id, _, _ = await extract_user(c, m) if user_id: if m.reply_to_message and m.reply_to_message.forward_from: user1 = m.reply_to_message.from_user user2 = m.reply_to_message.forward_from - orig_sender = ((await mention_html(user2.first_name, user2.id)),) - orig_id = (f"{user2.id}",) - fwd_sender = ((await mention_html(user1.first_name, user1.id)),) - fwd_id = (f"{user1.id}",) + orig_sender = await mention_html(user2.first_name, user2.id) + orig_id = f"{user2.id}" + fwd_sender = await mention_html(user1.first_name, user1.id) + fwd_id = f"{user1.id}" await m.reply_text( text=f"""Original Sender - {orig_sender} ({orig_id}) - Forwarder - {fwd_sender} ({fwd_id})""", +Forwarder - {fwd_sender} ({fwd_id})""", parse_mode=enums.ParseMode.HTML, ) else: @@ -176,9 +191,10 @@ async def id_info(c: Gojo, m: Message): text+=f"Forwarded from user ID {m.forward_from.id}." elif m.forward_from_chat: text+=f"Forwarded from user ID {m.forward_from_chat.id}." - await m.reply_text() + await m.reply_text(text) else: - await m.reply_text(text=f"This Group's ID is {m.chat.id}\nYour ID {m.from_user.id}") + text=f"Chat ID {m.chat.id}\nYour ID {m.from_user.id}" + await m.reply_text(text) return @@ -209,14 +225,17 @@ async def github(_, m: Message): f"Usage: {Config.PREFIX_HANDLER}github username", ) return - username = username.split("/")[-1] + username = username.split("/")[-1].strip("@") URL = f"https://api.github.com/users/{username}" try: - r = await get(URL, timeout=5) - except asyncio.TimeoutError: + r = get(URL, timeout=5) + except requests.exceptions.ConnectTimeout: return await m.reply_text("request timeout") except Exception as e: - return await m.reply_text(f"ERROR: `{e}`") + return await m.reply_text(f"ERROR:\n`{e}`") + if r.status_code != 200: + await m.reply_text(f"{username} this user is not available on github\nMake sure you have given correct username") + return avtar = r.get("avatar_url", None) url = r.get("html_url", None) @@ -226,10 +245,10 @@ async def github(_, m: Message): following = r.get("following", 0) public_repos = r.get("public_repos", 0) bio = r.get("bio", None) - created_at = r.get("created_at", "Not Found") + created_at = r.get("created_at", "NA").replace("T", " ").replace("Z","") location = r.get("location", None) email = r.get("email", None) - updated_at = r.get("updated_at", "Not Found") + updated_at = r.get("updated_at", "NA").replace("T", " ").replace("Z","") blog = r.get("blog", None) twitter = r.get("twitter_username", None) @@ -254,10 +273,12 @@ async def github(_, m: Message): REPLY += f"\nโšœ๏ธ Twitter: {twitter}" if location: REPLY += f"\n๐Ÿš€ Location: {location}" - REPLY += f"\n๐Ÿ’ซ Created at: {created_at}" - REPLY += f"\nโŒš๏ธ Updated at: {updated_at}" + if created_at != "NA": + REPLY += f"\n๐Ÿ’ซ Created at: {created_at}" + if updated_at != "NA": + REPLY += f"\nโŒš๏ธ Updated at: {updated_at}" if bio: - REPLY += f"\n\n๐ŸŽฏ Bio: {bio}" + REPLY += f"\n\n๐ŸŽฏ Bio: {bio}" if avtar: return await m.reply_photo(photo=f"{avtar}", caption=REPLY) @@ -266,14 +287,14 @@ async def github(_, m: Message): pattern = re.compile(r"^text/|json$|yaml$|xml$|toml$|x-sh$|x-shellscript$") -BASE = "https://batbin.me/" +BASE = "https://nekobin.com/" -async def paste(content: str): - resp = await post(f"{BASE}api/v2/paste", data=content) - if not resp["success"]: +def paste(content: str): + resp = resp_post(f"{BASE}api/documents", data=content) + if resp.status_code != 200: return - return BASE + resp["message"] + return BASE + resp["result"]['key'] @Gojo.on_message(command("paste")) @@ -289,7 +310,7 @@ async def paste_func(_, message: Message): return await m.edit("Only text and documents are supported") if r.text: - content = str(r.text) + content = {'content':f'{r.text}'} if r.document: if r.document.file_size > 40000: return await m.edit("You can only paste files smaller than 40KB.") @@ -300,11 +321,14 @@ async def paste_func(_, message: Message): doc = await message.reply_to_message.download() async with aiofiles.open(doc, mode="r") as f: - content = await f.read() + fdata = await f.read() + content = {'content':fdata} remove(doc) - - link = await paste(content) + link = paste(content) + if not link: + await m.reply_text("Failed to post!") + return kb = [[InlineKeyboardButton(text="Paste Link ", url=link)]] await m.delete() try: @@ -347,9 +371,32 @@ async def tr(_, message): f"Translated: from {detectlang} to {target_lang} \n``{tekstr.text}``", ) +@Gojo.on_message(command("bug")) +async def reporting_query(c: Gojo, m: Message): + repl = m.reply_to_message + if not repl: + await m.reply_text("Please reply to a message to report it as bug") + return + if not repl.text: + await m.reply_text("Please reply to a text message.") + return + txt = "#BUG\n" + txt += repl.text.html + txt += f"\nReported by: {m.from_user.id} ({m.from_user.mention})" + kb = InlineKeyboardMarkup([[InlineKeyboardButton("Update channel",url=f"https://t.me/{SUPPORT_GROUP}")],[InlineKeyboardButton("Report on github",url="https://github.com/Gojo-Bots/Gojo_Satoru/issues/new/choose")]]) + try: + z = await c.send_message(MESSAGE_DUMP,txt,parse_mode=enums.ParseMode.HTML) + except Exception: + txt = repl.text.html + z = await c.send_message(MESSAGE_DUMP,txt,parse_mode=enums.ParseMode.HTML) + await z.reply_text(f"#BUG\nReported by: {m.from_user.id} ({m.from_user.mention})") + await m.reply_text("Successfully reported your bug",reply_markup=kb) + ppost = z.link + 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"] +_DISABLE_CMDS_ = ["paste", "wiki", "id", "gifid", "tr", "github", "git", "bug"] __alt_name__ = ["util", "misc", "tools"] __HELP__ = """ @@ -365,6 +412,7 @@ async def tr(_, message): โ€ข /tr ``: Translates the text and then replies to you with the language you have specifed, works as a reply to message. โ€ข /git ``: Search for the user using github api! โ€ข /weebify `` or ``: To weebify the text. +โ€ข /bug : To report a bug **Example:** `/git iamgojoof6eyes`: this fetches the information about a user from the database.""" diff --git a/Powers/plugins/watchers.py b/Powers/plugins/watchers.py index 55e6bfb2..bc455f8d 100644 --- a/Powers/plugins/watchers.py +++ b/Powers/plugins/watchers.py @@ -5,7 +5,6 @@ from pyrogram import filters from pyrogram.errors import ChatAdminRequired, RPCError, UserAdminInvalid from pyrogram.types import ChatPermissions, Message -from RiZoeLX.functions import update_scanlist from Powers import LOGGER, MESSAGE_DUMP, SUPPORT_STAFF from Powers.bot_class import Gojo @@ -167,8 +166,6 @@ async def perform_action_blacklist(m: Message, action: str, trigger: str): return -SCANLIST = [] - @Gojo.on_message(filters.user(list(ANTISPAM_BANNED)) & filters.group) async def gban_watcher(c: Gojo, m: Message): @@ -210,20 +207,7 @@ async def gban_watcher(c: Gojo, m: Message): Error: {ef}""", ) - elif m.from_user.id in SCANLIST: - msg = f""" -** Alert โš ๏ธ** -User {m.from_user.mention} is officially -Scanned by TeamRed7 | Phoenix API ;) -Appeal [Here](https://t.me/Red7WatchSupport) - """ - try: - await c.ban_chat_member(m.chat.id, m.from_user.id) - await c.send_message(m.chat.id, msg, disable_web_page_preview=True) - except Exception as a: - LOGGER.error(a) - LOGGER.error(format_exc()) - return + @Gojo.on_message(filters.chat(BLACKLIST_CHATS)) diff --git a/Powers/plugins/web_con.py b/Powers/plugins/web_con.py new file mode 100644 index 00000000..22a51971 --- /dev/null +++ b/Powers/plugins/web_con.py @@ -0,0 +1,300 @@ +import asyncio +import os +from traceback import format_exc + +from pyrogram import filters +from pyrogram.types import CallbackQuery +from pyrogram.types import InlineKeyboardButton as IKB +from pyrogram.types import InlineKeyboardMarkup as IKM +from pyrogram.types import Message + +from Powers import (LOGGER, RMBG, Audd, genius_lyrics, is_audd, + is_genius_lyrics, is_rmbg) +from Powers.bot_class import Gojo +from Powers.utils.custom_filters import command +from Powers.utils.http_helper import * +from Powers.utils.sticker_help import toimage +from Powers.utils.web_helpers import * + + +@Gojo.on_message(command(["telegraph","tgh","tgm"])) +async def telegraph_upload(c:Gojo,m:Message): + if not m.reply_to_message: + await m.reply_text("Reply to media/text to upload it to telegraph") + return + XnX = await m.reply_text("โณ") + file = m.reply_to_message + if file.text: + if len(m.command) == 1: + name = file.from_user.first_name + file.text.split()[1] + elif len(m.command) > 1: + name = " ".join(m.command[1:5]) + try: + upload = await telegraph_up(file,name) + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + return + if upload: + await XnX.delete() + kb = IKM([[IKB("Here is link to the uploaded text",url=upload)]]) + await m.reply_text("Here is your uploaded text",disable_web_page_preview=True,reply_markup=kb) + return + elif not upload: + await m.reply_text("Failed to upload the text to telegraph") + return + if m.reply_to_message.photo or m.reply_to_message.document or m.reply_to_message.audio or m.reply_to_message.video: + size = await get_file_size(m.reply_to_message) + form = size.split(None,1) + if (form[-1] == "mb" and int(form[0]) > 5) or form[-1] == "gb": + await XnX.edit_text("File size too big to upload\nLimit: 5mbs") + return + await XnX.delete() + try: + upload = await telegraph_up(file) + except Exception as e: + await m.reply_text(f"Got an error\n{e}") + return + if upload: + kb = IKM([[IKB("Here is link to the file",url=upload)]]) + await m.reply_text(f"Here is your file link\n`{upload}`",reply_markup=kb) + return + elif not upload: + await m.reply_text("Failed to upload the file to telegraph") + return + +# @Gojo.on_message(command(["songname","insong","songinfo","whichsong","rsong","reversesong"])) +# โ€ข /whichsong (/songname, /songinfo, /insong, /rsong, /reversesong) : Reply to file to get the song playing in it. +# async def get_song_info(c: Gojo, m: Message): +# if not is_audd: +# await m.reply_text("Audd api is missing add it to use this command") +# return +# reply = m.reply_to_message +# if not reply: +# await m.reply_text("Reply to a video or audio file") +# return +# elif reply.text: +# await m.reply_text("Reply to a video or audio file") +# return +# elif not (reply.video or reply.audio or reply.video_note or reply.document and (reply.document.mime_type.split("/")[0] in ["video","audio"])): +# await m.reply_text("Reply to a video or audio file") +# return +# try: +# XnX = await m.reply_text("โณ") +# URL = "https://api.audd.io/" +# sizee = (await get_file_size(reply)).split() +# if (int(sizee[0]) <= 30 and sizee[1] == "mb") or sizee[1] == "kb": +# fpath = await reply.download() +# files = { +# "file" : open(fpath,"rb") +# } +# BASE_AUDD = { +# "api_token":Audd, +# "return": "spotify" +# } +# result = resp_post(URL,data=BASE_AUDD, files=files) +# # elif int(sizee[0]) > 15 or int(sizee[0]) <= 30 and sizee[1] == "mb": +# # BASE_AUDD = { +# # "api_token":Audd, +# # "url": f'{reply.link}', +# # "return": "spotify" +# # } +# # result = resp_post(URL,data=BASE_AUDD) +# else: +# await XnX.edit_text("File size too big\nI can only fetch file of size upto 30 mbs for now") +# return +# if result.status_code != 200: +# await XnX.edit_text(f"{result.status_code}:{result.text}") +# return +# result = result.json() +# data = result["result"] +# Artist = data["artist"] +# Title = data["title"] +# Release_date = data["release_date"] +# web_slink = data["song_link"] +# SPOTIFY = data["spotify"] +# spotify_url = SPOTIFY["external_urls"] +# album_url = SPOTIFY["album"]["external_urls"] +# Album = SPOTIFY["album"]["name"] +# photo = SPOTIFY["images"][0]["url"] +# artist_url = SPOTIFY["artists"]["external_urls"] +# cap = f""" +# Song name: {Title} +# Artist: {Artist} +# Album: {Album} +# Release data: {Release_date} +# """ +# youtube_link = (await song_search(Title))[1]["link"] +# kb = [ +# [ +# IKB("๐Ÿ—‚ Album", url=album_url), +# IKB("๐ŸŽจ Artist",url=artist_url) +# ], +# [ +# IKB("๐ŸŽต Spotify song link",url=spotify_url), +# IKB("โ–ถ๏ธ Youtube",url=youtube_link) +# ], +# [IKB("โ™พ More links", url=web_slink)] +# ] +# if is_genius_lyrics: +# g_k = [IKB("๐Ÿ“ Lyrics",f"lyrics_{Title}:{Artist}")] +# kb.append(g_k) +# await XnX.delete() +# os.remove(fpath) +# await m.reply_photo(photo,caption=cap,reply_markup=IKM(kb)) +# except Exception as e: +# await XnX.delete() +# await m.reply_text(f"Error\n{e}") +# try: +# os.remove(fpath) +# except Exception: +# pass +# return + + +@Gojo.on_callback_query(filters.regex("^lyrics_")) +async def lyrics_for_song(c: Gojo, q: CallbackQuery): + data = q.data.split("_")[1].split(":") + song = data[0] + try: + artist = data[1] + except IndexError: + artist = None + if artist: + song = genius_lyrics.search_song(song,artist) + elif not artist: + song = genius_lyrics.search_song(song) + if not song.lyrics: + await q.answer("โ€ผ๏ธ No lyrics found โ€ผ๏ธ",True) + return + header = f"{song.capitalize()} by {artist}" + if song.lyrics: + await q.answer("Fetching lyrics") + reply = song.lyrics.split("\n",1)[1] + if len(reply) >= 4096: + link = telegraph_up(name=header,content=reply) + cap = "Lyrics was too long\nUploaded it to telegraph" + new_kb = [ + [ + IKB("Telegraph",url=link) + ], + [ + IKB("Close","f_close") + ] + ] + else: + cap = f"{header}\n{reply}" + new_kb = [ + [ + IKB("Close","f_close") + ] + ] + await q.message.reply_to_message.reply_text(cap,reply_markup=new_kb) + await q.message.delete() + return + +@Gojo.on_message(command(["removebackground","removebg","rmbg"])) +async def remove_background(c: Gojo, m: Message): + if not is_rmbg: + await m.reply_text("Add rmbg api to use this command") + return + + reply = m.reply_to_message + if not reply: + await m.reply_text("Reply to image/sticker to remove it's background") + return + elif not (reply.photo or (reply.document and reply.document.mime_type.split("/")[0] == "image") or reply.sticker): + await m.reply_text("Reply to image/sticker to remove it's background") + return + elif reply.sticker and (reply.sticker.is_video or reply.sticker.is_animated): + await m.reply_text("Reply to normal sticker to remove it's background") + return + XnX = await m.reply_text("โณ") + URL = "https://api.remove.bg/v1.0/removebg" + if reply.sticker: + filee = await reply.download() + file = toimage(filee) + else: + file = await reply.download() + finfo = {'image_file':open(file,'rb')} + Data = {'size':'auto'} + Headers = {'X-Api-Key':RMBG} + result = resp_post(URL,files=finfo,data=Data,headers=Headers) + await XnX.delete() + contentType = result.headers.get("content-type") + if result.status_code != 200: + await m.reply_text(f"{result.status_code}:{result.text}") + os.remove(file) + return + elif "image" not in contentType: + await m.reply_text(f"Error\n{result.content.decode('UTF-8')}") + os.remove(file) + return + to_path = "./downloads" + if reply.sticker: + to_path = f'{to_path}/no-bg.webp' + else: + to_path = f'{to_path}/no-bg.png' + with open(to_path,'wb') as out: + out.write(result.content) + if reply.sticker: + await m.reply_sticker(to_path) + else: + await m.reply_photo(to_path) + try: + os.remove(file) + os.remove(to_path) + except PermissionError: + await asyncio.sleep(5) + return + +@Gojo.on_message(command(["song","yta"])) +async def song_down_up(c: Gojo, m: Message): + splited = m.text.split(None,1)[1].strip() + if splited.startswith("https://youtube.com"): + is_direct = True + query = splited + else: + is_direct = False + query = splited + XnX = await m.reply_text("โณ") + try: + await youtube_downloader(c,m,query,is_direct,"a") + await XnX.delete() + return + except Exception as e: + await XnX.edit_text(f"Got an error\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + +@Gojo.on_message(command(["vsong","ytv"])) +async def video_down_up(c: Gojo, m: Message): + splited = m.text.split(None,1)[1].strip() + if splited.startswith("https://youtube.com"): + is_direct = True + query = splited + else: + is_direct = False + query = splited + XnX = await m.reply_text("โณ") + try: + await youtube_downloader(c,m,query,is_direct,"v") + await XnX.delete() + return + except Exception as e: + await XnX.edit_text(f"Got an error\n{e}") + LOGGER.error(e) + LOGGER.error(format_exc()) + return + +__PLUGIN__ = "web support" + +__HELP__ = """ +**Available commands** +โ€ข /telegraph (/tgh, /tgm) : Reply to media which you want to upload to telegraph. +โ€ข /rmbg (/removebg, /removebackground) : Reply to image file or sticker of which you want to remove background +โ€ข /song (/yta) +โ€ข /vsong (/ytv) + +**Bot will not download any song or video having duration greater than 10 minutes (to reduce the load on bot's server)** +""" \ No newline at end of file diff --git a/Powers/utils/custom_filters.py b/Powers/utils/custom_filters.py index 04b33025..7cc7c444 100644 --- a/Powers/utils/custom_filters.py +++ b/Powers/utils/custom_filters.py @@ -156,6 +156,8 @@ async def admin_check_func(_, __, m: Message or CallbackQuery): if m.sender_chat: return True + if not m.from_user: + return False try: admin_group = {i[0] for i in ADMIN_CACHE[m.chat.id]} @@ -183,6 +185,9 @@ async def owner_check_func(_, __, m: Message or CallbackQuery): if m.chat.type not in [ChatType.SUPERGROUP, ChatType.GROUP]: return False + + if not m.from_user: + return False user = await m.chat.get_member(m.from_user.id) @@ -209,10 +214,12 @@ async def restrict_check_func(_, __, m: Message or CallbackQuery): ): return False + if not m.from_user: + return False user = await m.chat.get_member(m.from_user.id) - if user.privileges.can_restrict_members or user.status == CMS.OWNER: + if user.status in [CMS.ADMINISTRATOR, CMS.OWNER] and user.privileges.can_restrict_members: status = True else: status = False @@ -229,10 +236,12 @@ async def promote_check_func(_, __, m): if m.chat.type not in [ChatType.SUPERGROUP, ChatType.GROUP]: return False + if not m.from_user: + return False user = await m.chat.get_member(m.from_user.id) - if user.privileges.can_promote_members or user.status == CMS.OWNER: + if user.status in [CMS.ADMINISTRATOR, CMS.OWNER] and user.privileges.can_promote_members: status = True else: status = False @@ -257,7 +266,7 @@ async def changeinfo_check_func(_, __, m): user = await m.chat.get_member(m.from_user.id) - if user.privileges.can_change_info or user.status == CMS.OWNER: + if user.status in [CMS.ADMINISTRATOR, CMS.OWNER] and user.privileges.can_change_info: status = True else: status = False @@ -285,7 +294,7 @@ async def can_pin_message_func(_, __, m): user = await m.chat.get_member(m.from_user.id) - if user.privileges.can_pin_messages or user.status == CMS.OWNER: + if user.status in [CMS.ADMINISTRATOR, CMS.OWNER] and user.privileges.can_pin_messages: status = True else: status = False diff --git a/Powers/utils/extras.py b/Powers/utils/extras.py index 20a667a1..eeff034e 100644 --- a/Powers/utils/extras.py +++ b/Powers/utils/extras.py @@ -690,3 +690,82 @@ "https://te.legra.ph/file/52d92a67f0c6ce0a9f89f.jpg", "https://te.legra.ph/file/d91e7353b3803a8148bfc.jpg", ] + + +birthday_wish = [ + "Wishing you a happy birthday filled with love and joy.", + "Hope your birthday is as wonderful as you are.", + "Happy birthday to someone who deserves a truly special day.", + "May your birthday be full of surprises and delight.", + "Wishing you a year filled with new adventures and accomplishments.", + "May your birthday be as sweet as cake and as joyful as the celebration.", + "Here's to a fabulous birthday and a year filled with blessings.", + "Sending you lots of love and warm wishes on your special day.", + "May your birthday be a time for reflection, relaxation, and joy.", + "Cheers to another year of making unforgettable memories!", + "May your birthday be filled with laughter, love, and good times.", + "Wishing you a birthday that's just as amazing as you are.", + "Here's to a year filled with love, happiness, and success.", + "May your birthday be filled with all the love and blessings you deserve.", + "Sending you warm wishes for a joyful and memorable birthday.", + "Wishing you a birthday that's as wonderful as you are.", + "May your birthday be a time to celebrate all the amazing things you've accomplished.", + "Here's to another year of blessings, love, and adventure.", + "Sending you lots of love, hugs, and birthday wishes.", + "May your birthday be full of sunshine, laughter, and good times.", + "Wishing you a year filled with happiness, success, and love.", + "Here's to a fantastic birthday and an even better year ahead!", + "May your birthday be a day filled with joy, love, and celebration.", + "Sending you lots of love and warm wishes on your special day.", + "Wishing you a birthday that's as bright and beautiful as you are.", + "May your birthday be full of love, laughter, and happiness.", + "Here's to a year filled with exciting adventures and new opportunities.", + "Wishing you a birthday that's just as amazing as you are.", + "May your birthday be a time to reflect on all the wonderful things in your life.", + "Sending you lots of love, hugs, and birthday wishes from afar.", + "Wishing you a year filled with love, laughter, and all your heart desires.", + "May your birthday be a time to relax, unwind, and enjoy the company of loved ones.", + "Here's to another year of blessings, love, and adventure.", + "Sending you warm wishes for a wonderful and unforgettable birthday.", + "Wishing you a birthday that's as special and unique as you are.", + "May your birthday be a time to cherish all the special moments and memories you've created.", + "Here's to a year filled with joy, laughter, and happiness.", + "Wishing you a birthday that's just as amazing as you are.", + "May your birthday be a time to celebrate your wonderful achievements and accomplishments.", + "Sending you lots of love, hugs, and birthday wishes to make your day extra special.", + "Wishing you a year filled with love, happiness, and all your heart's desires.", + "May your birthday be a time to create new memories and cherish old ones.", + "Here's to another year of blessings, love, and adventure.", + "Sending you warm wishes for a fabulous and unforgettable birthday.", + "Wishing you a birthday that's full of love, laughter, and happiness.", + "May your birthday be a time to appreciate all the wonderful people in your life.", + "Wishing you a birthday as amazing as you are, filled with joy and memories to last a lifetime.", + "May your birthday be full of laughter and love, and your year be full of happiness and success.", + "Happy birthday to someone who makes the world a better place, may all your wishes come true.", + "Sending you warm birthday wishes and virtual hugs, can't wait to celebrate in person!", + "May your birthday be as special as you are, surrounded by all the people who love you the most.", + "Wishing you a day filled with laughter, and a year filled with new adventures and opportunities.", + "Happy birthday to someone who's always there to brighten up my day, may your day be as bright as you are.", + "Here's to a birthday that's just as awesome as you are, and a year filled with love and happiness.", + "May your birthday be a time to reflect on all the wonderful memories you've made, and look forward to new ones.", + "Wishing you a birthday that's full of surprises and excitement, and a year filled with new beginnings.", + "Happy birthday to my favorite person in the world, may your day be as special as you are to me.", + "Sending you the biggest birthday hugs and all my love, may your day be filled with joy and celebration.", + "May your birthday be a time to celebrate all your accomplishments and be proud of all you've achieved.", + "Wishing you a birthday that's as bright and beautiful as you are, filled with love and laughter.", + "Happy birthday to a true gem, may your day be filled with joy, laughter, and all the things you love.", + "Here's to a birthday that's full of happiness, excitement, and all the people who make your life special.", + "May your birthday be a time to let loose and have fun, and your year be filled with growth and success.", + "Wishing you a birthday that's full of all the things you love, and a year that's even better than the last.", + "Happy birthday to someone who makes my life brighter, may your day be as amazing as you are.", + "Sending you lots of love and virtual hugs on your special day, may your year be filled with blessings.", + "May your birthday be a time to cherish all the people who make your life special, and celebrate the person you've become.", + "Wishing you a birthday that's as unique and wonderful as you are, filled with love and laughter.", + "Happy birthday to someone who's always been there for me, may your day be filled with joy and celebration.", + "Here's to a birthday that's full of love, happiness, and all the things that bring you the most joy.", + "May your birthday be a time to reflect on all the amazing things you've accomplished, and look forward to all that's to come.", + "Wishing you a birthday that's full of surprises, happiness, and all the things that make you feel alive.", + "Happy birthday to someone who brings a smile to my face every day, may your day be as wonderful as you are.", + "Sending you all my love and warmest wishes on your special day, may your year be filled with love and happiness.", + "May your birthday be a time to appreciate all the people who make your life special, and cherish all the memories you've created.", + "Wishing you a birthday that's as beautiful as you are, filled with joy and celebration.",] \ No newline at end of file diff --git a/Powers/utils/http_helper.py b/Powers/utils/http_helper.py index a741fa76..8b9d68b5 100644 --- a/Powers/utils/http_helper.py +++ b/Powers/utils/http_helper.py @@ -1,36 +1,34 @@ from asyncio import gather # from Powers.bot_class import aiohttpsession as session -import aiohttp - -async def get(url: str, *args, **kwargs): - async with aiohttp.ClientSession() as session: - async with session.get(url, *args, **kwargs) as resp: - try: - data = await resp.json() - except Exception: - data = await resp.text() - return data - - -async def head(url: str, *args, **kwargs): - async with aiohttp.ClientSession() as session: - async with session.head(url, *args, **kwargs) as resp: - try: - data = await resp.json() - except Exception: - data = await resp.text() - return data - - -async def post(url: str, *args, **kwargs): - async with aiohttp.ClientSession() as session: - async with session.post(url, *args, **kwargs) as resp: - try: - data = await resp.json() - except Exception: - data = await resp.text() - return data +import requests + + +def get(url: str, *args, **kwargs): + resp = requests.get(url, *args, **kwargs) + try: + data = resp.json() + except Exception: + data = resp.text() + return data + + +def head(url: str, *args, **kwargs): + resp = requests.head(url, *args, **kwargs) + try: + data = resp.json() + except Exception: + data = resp.text() + return data + + +def post(url: str, *args, **kwargs): + resp = requests.post(url, *args, **kwargs) + try: + data = resp.json() + except Exception: + data = resp.text() + return data async def multiget(url: str, times: int, *args, **kwargs): @@ -45,9 +43,9 @@ async def multipost(url: str, times: int, *args, **kwargs): return await gather(*[post(url, *args, **kwargs) for _ in range(times)]) -async def resp_get(url: str, *args, **kwargs): - return await session.get(url, *args, **kwargs) +def resp_get(url: str, *args, **kwargs): + return requests.get(url, *args, **kwargs) -async def resp_post(url: str, *args, **kwargs): - return await session.post(url, *args, **kwargs) +def resp_post(url: str, *args, **kwargs): + return requests.post(url, *args, **kwargs) diff --git a/Powers/utils/start_utils.py b/Powers/utils/start_utils.py index b7593ecc..76a9a309 100644 --- a/Powers/utils/start_utils.py +++ b/Powers/utils/start_utils.py @@ -49,7 +49,15 @@ async def gen_start_kb(q: Message or CallbackQuery): "url", ), ], - [("๐Ÿ“š Commands & Help", "commands")], + [ + ( + "๐Ÿ“š Commands & Help", "commands" + ), + ( + "๐Ÿ‘พ Bot info", + "bot_curr_info" + ) + ], [ ( "๐Ÿ—ƒ๏ธ Source Code", @@ -58,8 +66,8 @@ async def gen_start_kb(q: Message or CallbackQuery): ), ( "Owner โค๏ธ", - f"https://t.me/{Config.owner_username}", - "url", + Config.OWNER_ID, + "user_id", ), ], [ @@ -216,12 +224,17 @@ async def get_private_rules(_, m: Message, help_option: str): quote=True, ) return "" + teks, button = await parse_button(rules) + button = await build_keyboard(button) + button = ikb(button) if button else None + textt = teks await m.reply_text( f"""The rules for {escape(chat_title)} are:\n -{rules} +{textt} """, quote=True, disable_web_page_preview=True, + reply_markup=button ) return "" @@ -255,7 +268,7 @@ async def get_help_msg(m: Message or CallbackQuery, help_option: str): ) else: help_msg = """ -Hey There! My name is Gojo. +Hey There! I am Gojo. I'm here to help you manage your groups! Commands available: ร— /start: Start the bot diff --git a/Powers/utils/sticker_help.py b/Powers/utils/sticker_help.py new file mode 100644 index 00000000..a68045d2 --- /dev/null +++ b/Powers/utils/sticker_help.py @@ -0,0 +1,263 @@ +import asyncio +import math +import os +import shlex +import textwrap +from typing import List, Tuple + +from PIL import Image, ImageDraw, ImageFont +from pyrogram import errors, raw +from pyrogram.file_id import FileId + +from Powers.bot_class import Gojo + + +async def get_sticker_set_by_name( + client: Gojo, name: str +) -> raw.base.messages.StickerSet: + try: + return await client.invoke( + raw.functions.messages.GetStickerSet( + stickerset=raw.types.InputStickerSetShortName(short_name=name), + hash=0, + ) + ) + except errors.exceptions.not_acceptable_406.StickersetInvalid: + return None + + + +async def create_sticker_set( + client: Gojo, + owner: int, + title: str, + short_name: str, + stickers: List[raw.base.InputStickerSetItem], + animated:bool=False, + video:bool=False +) -> raw.base.messages.StickerSet: + return await client.invoke( + raw.functions.stickers.CreateStickerSet( + user_id=await client.resolve_peer(owner), + title=title, + short_name=short_name, + stickers=stickers, + animated=animated, + videos=video + ) + ) + + +async def add_sticker_to_set( + client: Gojo, + stickerset: raw.base.messages.StickerSet, + sticker: raw.base.InputStickerSetItem, +) -> raw.base.messages.StickerSet: + return await client.invoke( + raw.functions.stickers.AddStickerToSet( + stickerset=raw.types.InputStickerSetShortName( + short_name=stickerset.set.short_name + ), + sticker=sticker, + ) + ) + + +async def create_sticker( + sticker: raw.base.InputDocument, emoji: str +) -> raw.base.InputStickerSetItem: + return raw.types.InputStickerSetItem(document=sticker, emoji=emoji) + + + +STICKER_DIMENSIONS = (512, 512) + + +async def resize_file_to_sticker_size(file_path: str,length:int=512,width:int=512) -> str: + im = Image.open(file_path) + if (im.width, im.height) < STICKER_DIMENSIONS: + size1 = im.width + size2 = im.height + if im.width > im.height: + scale = length / size1 + size1new = length + size2new = size2 * scale + else: + scale = width / size2 + size1new = size1 * scale + size2new = width + size1new = math.floor(size1new) + size2new = math.floor(size2new) + sizenew = (size1new, size2new) + im = im.resize(sizenew) + else: + im.thumbnail(STICKER_DIMENSIONS) + + file_pathh = "./downloads/resized.png" + im.save(file_pathh) + os.remove(file_path) + return file_pathh + + + +async def upload_document( + client: Gojo, file_path: str, chat_id: int +) -> raw.base.InputDocument: + media = await client.invoke( + raw.functions.messages.UploadMedia( + peer=await client.resolve_peer(chat_id), + media=raw.types.InputMediaUploadedDocument( + mime_type=client.guess_mime_type(file_path) or "application/zip", + file=await client.save_file(file_path), + attributes=[ + raw.types.DocumentAttributeFilename( + file_name=os.path.basename(file_path) + ) + ], + force_file=True, + ), + ) + ) + return raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference, + ) + + +async def get_document_from_file_id( + file_id: str, +) -> raw.base.InputDocument: + decoded = FileId.decode(file_id) + return raw.types.InputDocument( + id=decoded.media_id, + access_hash=decoded.access_hash, + file_reference=decoded.file_reference, + ) + +async def draw_meme(image_path, text:str,stick): + """Hellbot se churaya hai hue hue hue...""" + img = Image.open(image_path) + i_width, i_height = img.size + m_font = ImageFont.truetype( + "./extras/comic.ttf", int((70 / 640) * i_width) + ) + if ";" in text: + upper_text, lower_text = text.split(";") + else: + upper_text = text + lower_text = "" + draw = ImageDraw.Draw(img) + current_h, pad = 10, 5 + if upper_text: + for u_text in textwrap.wrap(upper_text,width=15,subsequent_indent=" "): + u_width, u_height = draw.textsize(u_text, font=m_font) + draw.text( + xy=(((i_width - u_width) / 2) - 1, int((current_h / 640) * i_width)), + text=u_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=(((i_width - u_width) / 2) + 1, int((current_h / 640) * i_width)), + text=u_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=((i_width - u_width) / 2, int(((current_h / 640) * i_width)) - 1), + text=u_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=(((i_width - u_width) / 2), int(((current_h / 640) * i_width)) + 1), + text=u_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=((i_width - u_width) / 2, int((current_h / 640) * i_width)), + text=u_text, + font=m_font, + fill=(255, 255, 255), + ) + current_h += u_height + pad + if lower_text: + for l_text in textwrap.wrap(upper_text,width=15,subsequent_indent=" "): + u_width, u_height = draw.textsize(l_text, font=m_font) + draw.text( + xy=( + ((i_width - u_width) / 2) - 1, + i_height - u_height - int((20 / 640) * i_width), + ), + text=l_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=( + ((i_width - u_width) / 2) + 1, + i_height - u_height - int((20 / 640) * i_width), + ), + text=l_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=( + (i_width - u_width) / 2, + (i_height - u_height - int((20 / 640) * i_width)) - 1, + ), + text=l_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=( + (i_width - u_width) / 2, + (i_height - u_height - int((20 / 640) * i_width)) + 1, + ), + text=l_text, + font=m_font, + fill=(0, 0, 0), + ) + draw.text( + xy=( + (i_width - u_width) / 2, + i_height - u_height - int((20 / 640) * i_width), + ), + text=l_text, + font=m_font, + fill=(255, 255, 255), + ) + current_h += u_height + pad + + hue = image_path + if stick: + stick_path = image_path + else: + stick_path = await resize_file_to_sticker_size(hue) + mee = tosticker(stick_path,"@memesofdank_memer_hu_vai.webp") + img.save(hue) + img.save(mee) + return hue, mee + +def toimage(image, filename=None): + filename = filename if filename else "gojo.jpg" + img = Image.open(image) + if img.mode != "RGB": + img = img.convert("RGB") + img.save(filename, "jpeg") + os.remove(image) + return filename + + +def tosticker(response, filename=None): + filename = filename if filename else "gojo.webp" + image = Image.open(response) + if image.mode != "RGB": + image.convert("RGB") + image.save(filename, "webp") + os.remove(response) + return filename \ No newline at end of file diff --git a/Powers/utils/string.py b/Powers/utils/string.py index 0180077c..487f408a 100644 --- a/Powers/utils/string.py +++ b/Powers/utils/string.py @@ -6,6 +6,7 @@ from pyrogram.enums import ChatType from pyrogram.types import InlineKeyboardButton, Message +from Powers import TIME_ZONE from Powers.utils.parser import escape_markdown BTN_URL_REGEX = compile_re(r"(\[([^\[]+?)\]\(buttonurl:(?:/{0,2})(.+?)(:same)?\))") @@ -19,7 +20,7 @@ async def extract_time(m: Message, time_val: str): if not time_num.isdigit(): await m.reply("Unspecified amount of time.") return "" - initial_time = datetime.now() + initial_time = datetime.now(TIME_ZONE) if unit == "m": bantime = initial_time + timedelta(minutes=int(time_num)) elif unit == "h": diff --git a/Powers/utils/web_helpers.py b/Powers/utils/web_helpers.py new file mode 100644 index 00000000..17ca6344 --- /dev/null +++ b/Powers/utils/web_helpers.py @@ -0,0 +1,274 @@ +import json +import os +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 +from telegraph import upload_file + +from Powers import telegraph +from Powers.bot_class import Gojo +from Powers.utils.http_helper import * + + +async def get_file_size(file: Message): + if file.photo: + size = file.photo.file_size/1024 + elif file.document: + size = file.document.file_size/1024 + elif file.video: + size = file.video.file_size/1024 + elif file.audio: + size = file.audio.file_size/1024 + elif file.sticker: + size = file.sticker.file_size/1024 + + if size <= 1024: + return f"{round(size)} kb" + elif size > 1024: + size = size/1024 + if size <= 1024: + return f"{round(size)} mb" + elif size > 1024: + size = size/1024 + return f"{round(size)} gb" + +async def telegraph_up(file:Message=None,name=None,content=None): + if not name: + name = "Captain_Ezio_Gojo_Bots" + if content: + page = telegraph.create_page(name,html_content=content) + if page: + return page['url'] + else: + return + if file.text: + to_upload = file.text.html + page = telegraph.create_page(name,html_content=to_upload) + if page: + return page['url'] + else: + return + doc = await file.download() + media_url = upload_file(doc) + tg_url = f"https://telegra.ph/{media_url[0]}" + os.remove(doc) + if tg_url: + return tg_url + else: + return + +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 + + +# 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 + yt_dict = {} + + nums = 1 + for i in results["videos"]: + durr = i['duration'].split(":") + if len(durr) == 3: + hour_to_sec = int(durr[0])*60*60 + minutes_to_sec = int(durr[1])*60 + total = hour_to_sec + minutes_to_sec + int(durr[2]) + if len(durr) == 2: + minutes_to_sec = int(durr[0])*60 + total = minutes_to_sec + int(durr[1]) + if not (total > 300): + 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] + } + yt_dict.update({nums: dict_form}) + nums += 1 + else: + pass + return yt_dict + +song_opts = { + "format": "bestaudio", + "addmetadata": True, + "key": "FFmpegMetadata", + "writethumbnail": True, + "prefer_ffmpeg": True, + "geo_bypass": True, + "nocheckcertificate": True, + "postprocessors": [ + { + "key": "FFmpegExtractAudio", + "preferredcodec": "mp3", + "preferredquality": "480", + } + ], + "outtmpl": "%(id)s.mp3", + "quiet": True, + "logtostderr": False, +} + + +video_opts = { + "format": "best", + "addmetadata": True, + "key": "FFmpegMetadata", + "prefer_ffmpeg": True, + "geo_bypass": True, + "nocheckcertificate": True, + "postprocessors": [ + { + "key": "FFmpegVideoConvertor", + "preferedformat": "mp4", + } + ], + "outtmpl": "%(id)s.mp4", + "logtostderr": False, + "quiet": True, +} + + + +async def youtube_downloader(c:Gojo,m:Message,query:str,is_direct:bool,type_:str): + if type_ == "a": + opts = song_opts + video = False + song = True + elif type_ == "v": + 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") + query = dicti[1]['link'] + FILE = ydl.extract_info(query,download=video) + if int(FILE['duration']) > 600: + 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'] + 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") + cap = f""" +โœ˜ Name: `{f_name}` +โœ˜ Views: `{views}` +""" + kb = IKM( + [ + [ + 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_path) + return + elif song: + await m.reply_audio(f_path,caption=cap,reply_markup=kb,duration=int(FILE['duration']),thumb=thumb,title=f_name) + os.remove(f_path) + os.remove(thumb) + return + + diff --git a/Powers/vars.py b/Powers/vars.py index d079226b..6172aa93 100644 --- a/Powers/vars.py +++ b/Powers/vars.py @@ -20,32 +20,36 @@ class Config: int(i) for i in config( "DEV_USERS", - default="1517994352 1344569458 1432756163 1874070588 1355478165 5301411431 1533682758", + default="", ).split(" ") ] SUDO_USERS = [ int(i) for i in config( "SUDO_USERS", - default="1344569458 1906306037", + default="", ).split(" ") ] WHITELIST_USERS = [ int(i) for i in config( "WHITELIST_USERS", - default="1344569458", + default="", ).split(" ") ] GENIUS_API_TOKEN = config("GENIUS_API") + AuDD_API = config("AuDD_API") + RMBG_API = config("RMBG_API") DB_URI = config("DB_URI", default="") DB_NAME = config("DB_NAME", default="") + BDB_URI = config("BDB_URI") NO_LOAD = config("NO_LOAD", default="").split() PREFIX_HANDLER = config("PREFIX_HANDLER", default="/").split() SUPPORT_GROUP = config("SUPPORT_GROUP", default="gojo_bots_network") SUPPORT_CHANNEL = config("SUPPORT_CHANNEL", default="gojo_bots_network") VERSION = config("VERSION", default="v2.0") WORKERS = int(config("WORKERS", default=16)) + TIME_ZONE = config("TIME_ZONE",default='Asia/Kolkata') BOT_USERNAME = "" BOT_ID = "" BOT_NAME = "" @@ -69,8 +73,12 @@ class Development: DB_NAME = "" # Your DB name NO_LOAD = [] GENIUS_API_TOKEN = "" + AuDD_API = "" + RMBG_API = "" PREFIX_HANDLER = ["!", "/"] SUPPORT_GROUP = "SUPPORT_GROUP" SUPPORT_CHANNEL = "SUPPORT_CHANNEL" VERSION = "VERSION" + TIME_ZONE = 'Asia/Kolkata' + BDB_URI = "" WORKERS = 8 diff --git a/README.md b/README.md index 4739ed19..7145f7d5 100644 --- a/README.md +++ b/README.md @@ -186,9 +186,20 @@ If all works well, bot should send message to the MESSAGE_DUMP Group!---> `DB_URI` Your [MongoDB](https://www.mongodb.com/) connection string. -`DB_NAME`: Your [MongoDB](https://www.mongodb.com/) database name. +`DB_NAME` Your [MongoDB](https://www.mongodb.com/) database name. + +`OWNER_ID` Your user ID as an integer. + +`GENIUS_API` Your Lyrics Genius Api Token. To fetch lyrics of songs. + +`AuDD_API` Your Audd api to get info of song by music file. + +`BDB_URI` Your mongodb uri different from previous one to store more info. + +`TIME_ZONE` Your time zone. + +`RMBG_API` Your removebackground api to remove the background/ -`OWNER_ID`: Your user ID as an integer. `SUPPORT_GROUP`: Your Telegram support group chat username where user's can contact in case of a problem. `MESSAGE_DUMP`: Event logs channel where bot will send updates. Note that id should starts with `-100`. @@ -267,19 +278,23 @@ To add your very own plugin just use the format given below and go through the [

---> -* [PSYREX](https://github.com/iamPSYREX) `for logos` +Some special thanks to the person/repo who/which helped and motivated me for creating this project + +* [PSYREX](https://github.com/iamPSYREX) for logos and motivatting me and giving me new ideas. * [Dan](https://github.com/delivrance) for [pyrogram](https://github.com/pyrogram/pyrogram) `library` -* [Alita_Robot](https://github.com/divideprojects/Alita_Robot) +* [Anand](https://github.com/HellBoy-OP) for helping me to enhance bot's security and look and also helping me out with various stuffs and bugs and also for motivating me to create this project. + +* [Alita_Robot](https://github.com/divideprojects/Alita_Robot) for base code. + --------- # Powered by [ษขึ…สึ… ษฎึ…ศถึ†](https://github.com/Gojo-Bots)

-

+ Gojo Bots

diff --git a/Version/version 2.1.1.md b/Version/version 2.1.1.md new file mode 100644 index 00000000..fa98cfd0 --- /dev/null +++ b/Version/version 2.1.1.md @@ -0,0 +1,22 @@ +# V 2.1.1 +### Changes made: +- Removed giveaway support to make bot faster. +- Added birthday wisher which will automatcally wish users at 12:00 AM on theri birthdays. +- Added some more commands, see web connection in bot to know the available commands. +- Added sticker kang option and few more commands, see stickers to know the available commands. +- Added **new lock types** +- Now using `/id ` will give the user's id as well. +- Now you can set url buttons while setting rules. +- Added `/bug` command to report the bug directly to the devs. +- Improved stability. +- Fixed known bugs. +- 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 Ezio](https://github.com/iamgojoof6eyes) \ No newline at end of file diff --git a/app.json b/app.json index 4c184088..36c7504f 100644 --- a/app.json +++ b/app.json @@ -87,6 +87,26 @@ "required": false, "value": "" }, + "AuDD_API" : { + "description": "Your Audd api to get info of song by music file", + "required": false, + "value": "" + }, + "BDB_URI": { + "description": "Your mongodb uri different from previous one to store more info", + "required": true, + "value": "" + }, + "TIME_ZONE": { + "description": "Your time zone", + "required": false, + "value": "Asia/Kolkata" + }, + "RMBG_API" : { + "description": "Your removebackground api to remove the background", + "required": false, + "value": "" + }, "WORKERS": { "description": "Number of workers to run the bot.", "required": false, @@ -99,6 +119,9 @@ } }, "buildpacks": [ + { + "url":"https://github.com/jonathanong/heroku-buildpack-ffmoeg-latest" + }, { "url": "heroku/python" } diff --git a/extras/Untitled(1).webp b/extras/Untitled(1).webp deleted file mode 100644 index dfa4d254..00000000 Binary files a/extras/Untitled(1).webp and /dev/null differ diff --git a/extras/comic.ttf b/extras/comic.ttf new file mode 100644 index 00000000..c4bd6c1e Binary files /dev/null and b/extras/comic.ttf differ diff --git a/extras/photo_2022-08-19_13-55-00.jpg b/extras/photo_2022-08-19_13-55-00.jpg deleted file mode 100644 index d4f12bee..00000000 Binary files a/extras/photo_2022-08-19_13-55-00.jpg and /dev/null differ diff --git a/requirements.txt b/requirements.txt index 70b9fbbe..c33ff0e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ aiofiles==23.1.0; python_full_version >= "3.7" -aiohttp==3.7.4; python_version >= "3.6" and python_version < "4.0" anyio==3.6.2; python_full_version >= "3.6.2" and python_version >= "3.6" +apscheduler==3.10.1 asyncio==3.4.3 beautifulsoup4==4.12.1; python_full_version >= "3.6" cachetools==5.2.0; python_version >= "3.7" and python_version < "4.0" @@ -11,22 +11,24 @@ google==3.0.0 gpytranslate==1.5.1; python_version >= "3.6" lyricsgenius==3.0.1 lxml==4.9.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" +pillow == 9.5.0 prettyconf==2.2.1 pyaes==1.6.1; python_version >= "3.6" and python_version < "4.0" pymongo==4.3.3 -pyRiZoeLX pyroaddon==1.0.6 pyrogram==2.0.103; 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") +pytz==2022.7.1 pyyaml==6.0; python_version >= "3.6" -regex==2023.3.23; python_version >= "3.6" +regex==2022.10.31; python_version >= "3.6" requests==2.28.2 rfc3986==1.5.0; python_version >= "3.7" search-engine-parser==0.6.8 six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" sniffio==1.3.0; python_full_version >= "3.6.2" and python_version >= "3.7" soupsieve==2.4; python_version >= "3.6" and python_full_version >= "3.6.0" +telegraph==2.2.0 tgcrypto==1.2.5; python_version >= "3.6" and python_version < "4.0" tswift==0.7.0 typing-extensions==4.5.0; python_full_version >= "3.6.2" and python_version >= "3.7" and python_version < "3.8"