Kaynağa Gözat

Added custom filters | improved stuffs

thehamkercat 5 yıl önce
ebeveyn
işleme
96262258dc

+ 0 - 1
requirements.txt

@@ -11,7 +11,6 @@ pillow
 psutil
 pykeyboard
 pyrogram
-pyromod
 python-arq
 requests
 search_engine_parser

+ 0 - 1
wbb/__init__.py

@@ -33,7 +33,6 @@ from motor.motor_asyncio import AsyncIOMotorClient as MongoClient
 from pyrogram import Client
 from Python_ARQ import ARQ
 
-from pyromod import listen
 
 # Setup logging
 log_file = "error.log"

+ 23 - 0
wbb/core/decorators/misc.py

@@ -1,3 +1,26 @@
+"""
+MIT License
+
+Copyright (c) 2021 TheHamkerCat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
 from functools import wraps
 from time import time
 

+ 4 - 4
wbb/core/decorators/permissions.py

@@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
 from functools import wraps
+from traceback import format_exc as err
 
 from pyrogram.errors.exceptions.forbidden_403 import ChatWriteForbidden
 from pyrogram.types import Message
@@ -37,10 +38,9 @@ async def authorised(func, subFunc2, client, message, *args, **kwargs):
     except ChatWriteForbidden:
         await app.leave_chat(chatID)
     except Exception as e:
-        try:
-            await message.reply_text(str(e))
-        except ChatWriteForbidden:
-            await app.leave_chat(chatID)
+        await message.reply_text(str(e.MESSAGE))
+        e = err()
+        print(str(e))
     return subFunc2
 
 

+ 109 - 0
wbb/core/filters.py

@@ -0,0 +1,109 @@
+"""
+MIT License
+
+Copyright (c) 2021 TheHamkerCat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
+from pyrogram import filters as filters_
+from pyrogram.types import Message
+
+from wbb import OWNER_ID, SUDOERS
+from wbb.modules.trust import get_spam_data
+from wbb.utils.functions import get_urls_from_text
+
+
+def url(_, __, message: Message) -> bool:
+    # Can't use entities to check for url because
+    # monospace removes url entity
+
+    # TODO Fix undetection of those urls which
+    # doesn't have schema, ex-facebook.com
+
+    text = message.text or message.caption
+    if not text:
+        return False
+    return bool(get_urls_from_text(text))
+
+
+async def spam(_, __, message: Message) -> bool:
+    text = message.text or message.caption
+    if not text:
+        return False
+    return (await get_spam_data(message, text)).is_spam
+
+
+async def admin(_, __, message: Message) -> bool:
+    if message.chat.type not in ["group", "supergroup"]:
+        return False
+    if not message.from_user:
+        if not message.sender_chat:
+            return False
+        return True
+    # Calling iter_chat_members again and again
+    # doesn't causes floodwaits, idk why, maybe it's
+    # cached or something, that's why using it.
+    return message.from_user.id in [
+        member.user.id
+        async for member in message._client.iter_chat_members(
+            message.chat.id, filter="administrators"
+        )
+    ]
+
+
+def entities(_, __, message: Message) -> bool:
+    return bool(message.entities)
+
+
+async def profanity(_, __, message: Message) -> bool:
+    text = message.text or message.caption
+    if not text:
+        return False
+    return (await get_spam_data(message, text)).profanity
+
+
+def anonymous(_, __, message: Message) -> bool:
+    return bool(message.sender_chat)
+
+
+def sudoers(_, __, message: Message) -> bool:
+    if not message.from_user:
+        return False
+    return message.from_user.id in SUDOERS
+
+
+def owner(_, __, message: Message) -> bool:
+    if not message.from_user:
+        return False
+    return message.from_user.id == OWNER_ID
+
+
+class Filters:
+    pass
+
+
+filters = Filters
+filters.url = filters_.create(url)
+filters.spam = filters_.create(spam)
+filters.admin = filters_.create(admin)
+filters.entities = filters_.create(entities)
+filters.profanity = filters_.create(profanity)
+filters.anonymous = filters_.create(anonymous)
+filters.sudoers = filters_.create(sudoers)
+filters.owner = filters_.create(owner)

+ 14 - 24
wbb/modules/images.py → wbb/core/keyboard.py

@@ -21,32 +21,22 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
-import asyncio
-import json
-import urllib.request
+from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
 
-from pyrogram import filters
+from wbb.utils.functions import get_urls_from_text
 
-from wbb import app
-from wbb.core.decorators.errors import capture_err
 
-__MODULE__ = "Images"
-__HELP__ = """/cat  - Get Cute Cats Images
-For more images search like wallpapers etc, use inline mode.
-"""
-
-
-async def delete_message_with_delay(delay, message):
-    await asyncio.sleep(delay)
-    await message.delete()
+def btn(text, data, type=None):
+    type = "url" if get_urls_from_text(data) else "callback_data"
+    return InlineKeyboardButton(text, **{type: data})
 
 
-@app.on_message(filters.command("cat") & ~filters.edited)
-@capture_err
-async def cat(_, message):
-    with urllib.request.urlopen(
-        "https://api.thecatapi.com/v1/images/search"
-    ) as url:
-        data = json.loads(url.read().decode())
-    cat_url = data[0]["url"]
-    await message.reply_photo(cat_url)
+def ikb(keyboard: list):
+    lines = []
+    for row in keyboard:
+        line = []
+        for button in row:
+            button = btn(*button)  # InlineKeyboardButton
+            line.append(button)
+        lines.append(line)
+    return InlineKeyboardMarkup(inline_keyboard=lines)

+ 23 - 0
wbb/core/types/InlineQueryResult.py

@@ -1,3 +1,26 @@
+"""
+MIT License
+
+Copyright (c) 2021 TheHamkerCat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
 from typing import List, Optional, Union
 
 import pyrogram

+ 142 - 144
wbb/modules/admin.py

@@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
 import asyncio
+from traceback import format_exc as err
 
 from pyrogram import filters
 from pyrogram.types import (CallbackQuery, ChatPermissions,
@@ -30,8 +31,10 @@ from pyrogram.types import (CallbackQuery, ChatPermissions,
 
 from wbb import BOT_ID, SUDOERS, app
 from wbb.core.decorators.errors import capture_err
+from wbb.core.keyboard import ikb
 from wbb.utils.dbfunctions import (add_warn, get_warn, int_to_alpha,
                                    remove_warns)
+from wbb.utils.functions import extract_user, extract_user_and_reason
 
 __MODULE__ = "Admin"
 __HELP__ = """/ban - Ban A User
@@ -54,7 +57,10 @@ __HELP__ = """/ban - Ban A User
 
 async def member_permissions(chat_id: int, user_id: int):
     perms = []
-    member = await app.get_chat_member(chat_id, user_id)
+    try:
+        member = await app.get_chat_member(chat_id, user_id)
+    except Exception:
+        return []
     if member.can_post_messages:
         perms.append("can_post_messages")
     if member.can_edit_messages:
@@ -139,7 +145,7 @@ async def purgeFunc(client, message: Message):
         return
     if not message.reply_to_message:
         return await message.reply_text(
-            "Reply To A Message To Delete From, Don't Make Fun Of Yourself!"
+            "Reply to a message to delete from, don't make fun of yourself!"
         )
     await message.delete()
     for a_s_message_id in range(
@@ -165,21 +171,28 @@ async def purgeFunc(client, message: Message):
 @app.on_message(filters.command("kick") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def kickFunc(_, message: Message):
-    if len(message.command) == 2:
-        user_id = (await app.get_users(message.text.split(None, 1)[1])).id
-    elif len(message.command) == 1 and message.reply_to_message:
-        user_id = message.reply_to_message.from_user.id
-    else:
+    user_id, reason = await extract_user_and_reason(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    if user_id == BOT_ID:
         return await message.reply_text(
-            "Provide a username or reply to a user's message to kick."
+            "I can't kick myself, i can leave if you want."
         )
     if user_id in SUDOERS:
-        await message.reply_text("You Wanna Kick The Elevated One?")
-    else:
-        await message.chat.kick_member(user_id)
-        await asyncio.sleep(1)
-        await message.reply_text("Kicked!")
-        await message.chat.unban_member(user_id)
+        return await message.reply_text("You Wanna Kick The Elevated One?")
+    if user_id in (await list_admins(message.chat.id)):
+        return await message.reply_text(
+            "I can't kick an admin, You know the rules, so do i."
+        )
+    mention = (await app.get_users(user_id)).mention
+    msg = f"""
+**Kicked User:** {mention}
+**Kicked By:** {message.from_user.mention if message.from_user else 'Anon'}
+**Reason:** {reason or 'No Reason Provided.'}"""
+    await message.chat.kick_member(user_id)
+    await message.reply_text(msg)
+    await asyncio.sleep(1)
+    await message.chat.unban_member(user_id)
 
 
 # Ban members
@@ -188,19 +201,28 @@ async def kickFunc(_, message: Message):
 @app.on_message(filters.command("ban") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def banFunc(_, message: Message):
-    if len(message.command) == 2:
-        user_id = (await app.get_users(message.text.split(None, 1)[1])).id
-    elif len(message.command) == 1 and message.reply_to_message:
-        user_id = message.reply_to_message.from_user.id
-    else:
+    user_id, reason = await extract_user_and_reason(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    if user_id == BOT_ID:
         return await message.reply_text(
-            "Provide a username or reply to a user's message to ban."
+            "I can't ban myself, i can leave if you want."
         )
     if user_id in SUDOERS:
-        await message.reply_text("You Wanna Ban The Elevated One?")
-    else:
-        await message.chat.kick_member(user_id)
-        await message.reply_text("Banned!")
+        return await message.reply_text(
+            "You Wanna Ban The Elevated One?, RECONSIDER!"
+        )
+    if user_id in (await list_admins(message.chat.id)):
+        return await message.reply_text(
+            "I can't ban an admin, You know the rules, so do i."
+        )
+    mention = (await app.get_users(user_id)).mention
+    msg = f"""
+**Banned User:** {mention}
+**Banned By:** {message.from_user.mention if message.from_user else 'Anon'}
+**Reason:** {reason or 'No Reason Provided.'}"""
+    await message.chat.kick_member(user_id)
+    await message.reply_text(msg)
 
 
 # Unban members
@@ -209,6 +231,10 @@ async def banFunc(_, message: Message):
 @app.on_message(filters.command("unban") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def unbanFunc(_, message: Message):
+    # we don't need reasons for unban, also, we
+    # don't need to get "text_mention" entity, because
+    # normal users won't get text_mention if the the user
+    # they want to unban is not in the group.
     if len(message.command) == 2:
         user = message.text.split(None, 1)[1]
     elif len(message.command) == 1 and message.reply_to_message:
@@ -239,17 +265,14 @@ async def deleteFunc(_, message: Message):
 @app.on_message(filters.command("promote") & ~filters.edited)
 @adminsOnly("can_promote_members")
 async def promoteFunc(_, message: Message):
-    chat_id = message.chat.id
-    bot = await app.get_chat_member(chat_id, BOT_ID)
-    if len(message.command) == 2:
-        username = message.text.split(None, 1)[1]
-        user_id = (await app.get_users(username)).id
-    elif len(message.command) == 1 and message.reply_to_message:
-        user_id = message.reply_to_message.from_user.id
-    else:
-        return await message.reply_text(
-            "Reply To A User's Message Or Give A Username To Promote."
-        )
+    user_id = await extract_user(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    bot = await app.get_chat_member(message.chat.id, BOT_ID)
+    if user_id == BOT_ID:
+        return await message.reply_text("I can't promote myself.")
+    if not bot.can_promote_members:
+        return await message.reply_text("I don't have enough permissions")
     await message.chat.promote_member(
         user_id=user_id,
         can_change_info=bot.can_change_info,
@@ -270,14 +293,18 @@ async def promoteFunc(_, message: Message):
 @app.on_message(filters.command("demote") & ~filters.edited)
 @adminsOnly("can_promote_members")
 async def demote(_, message: Message):
-    if len(message.command) == 2:
-        username = message.text.split(None, 1)[1]
-        user_id = (await app.get_users(username)).id
-    elif len(message.command) == 1 and message.reply_to_message:
-        user_id = message.reply_to_message.from_user.id
-    else:
+    user_id = await extract_user(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    if user_id == BOT_ID:
+        return await message.reply_text("I can't demote myself.")
+    if user_id in SUDOERS:
+        return await message.reply_text(
+            "You wanna demote the elevated one?, RECONSIDER!"
+        )
+    if user_id in (await list_admins(message.chat.id)):
         return await message.reply_text(
-            "Reply To A User's Message Or Give A Username To Demote."
+            "I can't demote an admin, You know the rules, so do i."
         )
     await message.chat.promote_member(
         user_id=user_id,
@@ -300,7 +327,7 @@ async def demote(_, message: Message):
 @adminsOnly("can_pin_messages")
 async def pin(_, message: Message):
     if not message.reply_to_message:
-        return await message.reply_text("Reply To A Message To Pin.")
+        return await message.reply_text("Reply to a message to pin it.")
     await message.reply_to_message.pin(disable_notification=True)
 
 
@@ -310,30 +337,27 @@ async def pin(_, message: Message):
 @app.on_message(filters.command("mute") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def mute(_, message: Message):
-    if len(message.command) == 2:
-        user = await app.get_users(message.text.split(None, 1)[1])
-    elif len(message.command) == 1 and message.reply_to_message:
-        user = message.reply_to_message.from_user
-    else:
+    user_id, reason = await extract_user_and_reason(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    if user_id == BOT_ID:
+        return await message.reply_text("I can't mute myself.")
+    if user_id in SUDOERS:
         return await message.reply_text(
-            "Provide a username or reply to a user's message to mute."
+            "You wanna mute the elevated one?, RECONSIDER!"
         )
-    if user.id in SUDOERS:
-        return await message.reply_text("You Wanna Mute The Elevated One?")
-    await message.chat.restrict_member(user.id, permissions=ChatPermissions())
-    keyboard = InlineKeyboardMarkup(
-        [
-            [
-                InlineKeyboardButton(
-                    text="🚨   Unmute   🚨", callback_data=f"unmute_{user.id}"
-                )
-            ]
-        ]
-    )
-    await message.reply_text(
-        f"Enough freedom of speech, Muted {user.mention} !",
-        reply_markup=keyboard,
-    )
+    if user_id in (await list_admins(message.chat.id)):
+        return await message.reply_text(
+            "I can't mute an admin, You know the rules, so do i."
+        )
+    await message.chat.restrict_member(user_id, permissions=ChatPermissions())
+    mention = (await app.get_users(user_id)).mention
+    keyboard = ikb([[("🚨   Unmute   🚨", f"unmute_{user_id}")]])
+    msg = f"""
+**Muted User:** {mention}
+**Muted By:** {message.from_user.mention if message.from_user else 'Anon'}
+**Reason:** {reason or 'No Reason Provided.'}"""
+    await message.reply_text(msg, reply_markup=keyboard)
 
 
 # Unmute members
@@ -342,15 +366,10 @@ async def mute(_, message: Message):
 @app.on_message(filters.command("unmute") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def unmute(_, message: Message):
-    if len(message.command) == 2:
-        user = message.text.split(None, 1)[1]
-    elif len(message.command) == 1 and message.reply_to_message:
-        user = message.reply_to_message.from_user.id
-    else:
-        return await message.reply_text(
-            "Provide a username or reply to a user's message to Unmute"
-        )
-    await message.chat.unban_member(user)
+    user_id = await extract_user(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    await message.chat.unban_member(user_id)
     await message.reply_text("Unmuted!")
 
 
@@ -381,57 +400,51 @@ async def ban_deleted_accounts(_, message: Message):
 @app.on_message(filters.command("warn") & ~filters.edited)
 @adminsOnly("can_restrict_members")
 async def warn_user(_, message: Message):
-    if not message.reply_to_message:
-        return await message.reply_text("Reply to a message to warn a user.")
+    user_id, reason = await extract_user_and_reason(message)
     chat_id = message.chat.id
-    user_id = message.reply_to_message.from_user.id
-    mention = message.reply_to_message.from_user.mention
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    if user_id == BOT_ID:
+        return await message.reply_text(
+            "I can't warn myself, i can leave if you want."
+        )
     if user_id in SUDOERS:
-        await message.reply_text("You Wanna Warn The Elevated One?")
-    elif user_id == BOT_ID:
-        await message.reply_text("Huh, Can't warn myself.")
-    elif user_id in await list_admins(message.chat.id):
-        await message.reply_text("Can't warn an admin.")
+        return await message.reply_text(
+            "You Wanna Warn The Elevated One?, RECONSIDER!"
+        )
+    if user_id in (await list_admins(chat_id)):
+        return await message.reply_text(
+            "I can't warn an admin, You know the rules, so do i."
+        )
+    if user_id not in (await list_members(chat_id)):
+        return await message.reply_text("This user isn't here.")
+    user, warns = await asyncio.gather(
+        app.get_users(user_id), get_warn(chat_id, await int_to_alpha(user_id))
+    )
+    mention = user.mention
+    keyboard = ikb([[("🚨  Remove Warn  🚨", f"unwarn_{user_id}")]])
+    if warns:
+        warns = warns["warns"]
     else:
-        if user_id in await list_members(chat_id):
-            warns = await get_warn(chat_id, await int_to_alpha(user_id))
-            keyboard = InlineKeyboardMarkup(
-                [
-                    [
-                        InlineKeyboardButton(
-                            text="🚨  Remove Warn  🚨",
-                            callback_data=f"unwarn_{user_id}",
-                        )
-                    ]
-                ]
-            )
-            if warns:
-                warns = warns["warns"]
-            else:
-                warn = {"warns": 1}
-                await add_warn(chat_id, await int_to_alpha(user_id), warn)
-                return await message.reply_text(
-                    f"Warned {mention} | 1/3 warnings now.",
-                    reply_markup=keyboard,
-                )
-            if warns >= 2:
-                await message.chat.kick_member(user_id)
-                await message.reply_text(
-                    f"Number of warns of {mention} exceeded, Banned!"
-                )
-                await remove_warns(chat_id, await int_to_alpha(user_id))
-            else:
-                warn = {"warns": warns + 1}
-
-                await message.reply_text(
-                    f"Warned {mention} | {warns+1}/3 warnings now.",
-                    reply_markup=keyboard,
-                )
-                return await add_warn(
-                    chat_id, await int_to_alpha(user_id), warn
-                )
-        else:
-            await message.reply_text("This user isn't here.")
+        warns = 0
+    if warns >= 2:
+        _, __, alpha = await asyncio.gather(
+            message.chat.kick_member(user_id),
+            message.reply_text(
+                "Number of warns of {mention} exceeded, BANNED!"
+            ),
+            int_to_alpha(user_id),
+        )
+        await remove_warns(chat_id, alpha)
+    else:
+        warn = {"warns": warns + 1}
+        msg = f"""
+**Warned User:** {mention}
+**Warned By:** {message.from_user.mention if message.from_user else 'Anon'}
+**Reason:** {reason or 'No Reason Provided.'}
+**Warns:** {warns + 1}/3"""
+        await message.reply_text(msg, reply_markup=keyboard)
+        await add_warn(chat_id, await int_to_alpha(user_id), warn)
 
 
 @app.on_callback_query(filters.regex("unwarn_"))
@@ -489,31 +502,16 @@ async def remove_warnings(_, message: Message):
 @app.on_message(filters.command("warns") & ~filters.edited)
 @capture_err
 async def check_warns(_, message: Message):
-    if not message.reply_to_message:
-        return await message.reply_text(
-            "Reply to a message to check a user's warnings."
-        )
-    user_id = message.reply_to_message.from_user.id
-    mention_user = message.reply_to_message.from_user.mention
-    mention_from_user = message.from_user.mention
-    chat_id = message.chat.id
-    if message.reply_to_message:
-        warns = await get_warn(chat_id, await int_to_alpha(user_id))
-        if warns:
-            warns = warns["warns"]
-        else:
-            return await message.reply_text(
-                f"{mention_user} have no warnings."
-            )
-        return await message.reply_text(
-            f"{mention_user} have {warns}/3 warnings."
-        )
-    warns = await get_warn(chat_id, await int_to_alpha(user_id))
+    user_id = await extract_user(message)
+    if not user_id:
+        return await message.reply_text("I can't find that user.")
+    warns = await get_warn(message.chat.id, await int_to_alpha(user_id))
+    mention = (await app.get_users(user_id)).mention
     if warns:
         warns = warns["warns"]
     else:
-        return await message.reply_text(f"{mention_user} have no warnings.")
-    await message.reply_text(f"{mention_from_user} have {warns}/3 warnings.")
+        return await message.reply_text(f"{mention} has no warnings.")
+    return await message.reply_text(f"{mention} has {warns}/3 warnings.")
 
 
 # Report

+ 4 - 0
wbb/modules/admin_misc.py

@@ -52,6 +52,10 @@ async def set_chat_title(_, message):
 @app.on_message(filters.command("set_user_title") & ~filters.private)
 @adminsOnly("can_change_info")
 async def set_user_title(_, message):
+    if not message.reply_to_message:
+        return await message.reply_text("Reply to user's message to set his admin title")
+    if not message.reply_to_message.from_user:
+        return await message.reply_text("I can't change admin title of an unknown entity")
     chat_id = message.chat.id
     from_user = message.reply_to_message.from_user
     if len(message.command) < 2:

+ 2 - 2
wbb/modules/carbon.py

@@ -24,6 +24,6 @@ async def carbon_func(_, message):
     m = await message.reply_text("Preparing Carbon")
     carbon = await make_carbon(message.reply_to_message.text)
     await m.edit("Uploading")
-    await app.send_photo(message.chat.id, carbon)
+    await app.send_document(message.chat.id, carbon)
     await m.delete()
-    os.remove(carbon)
+    carbon.close()

+ 39 - 69
wbb/modules/chatbot.py

@@ -21,7 +21,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
+from asyncio import sleep, gather
 from pyrogram import filters
+from pyrogram.types import Message
 
 from wbb import (BOT_ID, SUDOERS, USERBOT_ID, USERBOT_PREFIX, USERBOT_USERNAME,
                  app, app2, arq)
@@ -37,43 +39,48 @@ __HELP__ = """
 active_chats_bot = []
 active_chats_ubot = []
 
-
-# Enabled | Disable Chatbot
-
-
-@app.on_message(filters.command("chatbot") & ~filters.edited)
-@capture_err
-async def chatbot_status(_, message):
-    global active_chats_bot
-    if len(message.command) != 2:
-        return await message.reply_text("**Usage**\n/chatbot [ON|OFF]")
-    status = message.text.split(None, 1)[1]
+async def chat_bot_toggle(db, message):
+    status = message.text.split(None, 1)[1].lower()
     chat_id = message.chat.id
-
-    if status == "ON" or status == "on" or status == "On":
-        if chat_id not in active_chats_bot:
-            active_chats_bot.append(chat_id)
+    if status == "on":
+        if chat_id not in db:
+            db.append(chat_id)
             text = (
                 "Chatbot Enabled Reply To Any Message "
                 + "Of Mine To Get A Reply"
             )
-            return await message.reply_text(text)
-        await message.reply_text("ChatBot Is Already Enabled.")
+            return await edit_or_reply(message, text=text)
+        await edit_or_reply(message, text="ChatBot Is Already Enabled.")
+    elif status == "off":
+        if chat_id in db:
+            db.remove(chat_id)
+            return await edit_or_reply(message, text="Chatbot Disabled!")
+        await edit_or_reply(message, text="ChatBot Is Already Disabled.")
+    else:
+        await edit_or_reply(message, text="**Usage**\n/chatbot [ON|OFF]")
 
-    elif status == "OFF" or status == "off" or status == "Off":
-        if chat_id in active_chats_bot:
-            active_chats_bot.remove(chat_id)
-            return await message.reply_text("Chatbot Disabled!")
-        await message.reply_text("ChatBot Is Already Disabled.")
+# Enabled | Disable Chatbot
 
-    else:
-        await message.reply_text("**Usage**\n/chatbot [ON|OFF]")
 
+@app.on_message(filters.command("chatbot") & ~filters.edited)
+@capture_err
+async def chatbot_status(_, message):
+    if len(message.command) != 2:
+        return await edit_or_reply(message, text="**Usage**\n/chatbot [ON|OFF]")
+    await chat_bot_toggle(active_chats_bot, message)
 
 async def lunaQuery(query: str, user_id: int):
     luna = await arq.luna(query, user_id)
     return luna.result
 
+async def type_and_send(message):
+    chat_id = message.chat.id
+    user_id = message.from_user.id if message.from_user else 0
+    query = message.text.strip()
+    await message._client.send_chat_action(chat_id, "typing")
+    response, _ = await gather(lunaQuery(query, user_id), sleep(3))
+    await message.reply_text(response)
+    await message._client.send_chat_action(chat_id, "cancel")
 
 @app.on_message(
     filters.text
@@ -91,13 +98,7 @@ async def chatbot_talk(_, message):
         return
     if message.reply_to_message.from_user.id != BOT_ID:
         return
-    query = message.text
-    await app.send_chat_action(message.chat.id, "typing")
-    response = await lunaQuery(
-        query, message.from_user.id if message.from_user else 0
-    )
-    await app.send_chat_action(message.chat.id, "cancel")
-    await message.reply_text(response)
+    await type_and_send(message)
 
 
 """ FOR USERBOT """
@@ -110,32 +111,11 @@ async def chatbot_talk(_, message):
 )
 @capture_err
 async def chatbot_status_ubot(_, message):
-    global active_chats_ubot
     if len(message.text.split()) != 2:
         return await edit_or_reply(
             message, text="**Usage**\n.chatbot [ON|OFF]"
         )
-    status = message.text.split(None, 1)[1]
-    chat_id = message.chat.id
-    if status == "ON" or status == "on" or status == "On":
-        if chat_id not in active_chats_ubot:
-            active_chats_ubot.append(chat_id)
-            text = (
-                "Chatbot Enabled Reply To Any Message "
-                + "Of Mine To Get A Reply"
-            )
-            return await edit_or_reply(message, text=text)
-        await edit_or_reply(message, text="ChatBot Is Already Enabled.")
-
-    elif status == "OFF" or status == "off" or status == "Off":
-        if chat_id in active_chats_ubot:
-            active_chats_ubot.remove(chat_id)
-            await edit_or_reply(message, text="Chatbot Disabled!")
-            return
-        await edit_or_reply(message, text="ChatBot Is Already Disabled.")
-
-    else:
-        await edit_or_reply(message, text="**Usage**\n/chatbot [ON|OFF]")
+    await chat_bot_toggle(active_chats_ubot, message)
 
 
 @app2.on_message(
@@ -147,22 +127,18 @@ async def chatbot_talk_ubot(_, message):
     if message.chat.id not in active_chats_ubot:
         return
     username = "@" + str(USERBOT_USERNAME)
-    query = message.text
     if message.reply_to_message:
+        if not message.reply_to_message.from_user:
+            return
         if (
             message.reply_to_message.from_user.id != USERBOT_ID
-            and username not in query
+            and username not in message.text
         ):
             return
     else:
-        if username not in query:
+        if username not in message.text:
             return
-    await app2.send_chat_action(message.chat.id, "typing")
-    response = await lunaQuery(
-        query, message.from_user.id if message.from_user else 0
-    )
-    await app2.send_chat_action(message.chat.id, "cancel")
-    await message.reply_text(response)
+    await type_and_send(message)
 
 
 @app2.on_message(
@@ -173,10 +149,4 @@ async def chatbot_talk_ubot(_, message):
 async def chatbot_talk_ubot_pm(_, message):
     if message.chat.id not in active_chats_ubot:
         return
-    query = message.text
-    await app2.send_chat_action(message.chat.id, "typing")
-    response = await lunaQuery(
-        query, message.from_user.id if message.from_user else 0
-    )
-    await message.reply_text(response)
-    await app2.send_chat_action(message.chat.id, "cancel")
+    await type_and_send(message)

+ 0 - 48
wbb/modules/covid.py

@@ -1,48 +0,0 @@
-"""
-MIT License
-
-Copyright (c) 2021 TheHamkerCat
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-"""
-from pyrogram import filters
-
-from wbb import app
-from wbb.core.decorators.errors import capture_err
-from wbb.utils.fetch import fetch
-from wbb.utils.json_prettify import json_prettify
-
-__MODULE__ = "Covid"
-__HELP__ = """/covid - To Get Global Stats of Covid.
-/covid [COUNTRY] - To Get Stats of A Single Country."""
-
-
-@app.on_message(filters.command("covid") & ~filters.edited)
-@capture_err
-async def covid(_, message):
-    if len(message.command) == 1:
-        data = await fetch("https://corona.lmao.ninja/v2/all")
-        data = await json_prettify(data)
-        return await app.send_message(message.chat.id, text=data)
-    if len(message.command) != 1:
-        country = message.text.split(None, 1)[1].strip()
-        country = country.replace(" ", "")
-        data = await fetch(f"https://corona.lmao.ninja/v2/countries/{country}")
-        data = await json_prettify(data)
-        await app.send_message(message.chat.id, text=data)

+ 1 - 1
wbb/modules/log.py

@@ -4,8 +4,8 @@ import aiofiles
 from pyrogram import filters
 from pyrogram.types import CallbackQuery, Message
 
-from pyromod.helpers import ikb
 from wbb import SUDOERS, app, log_file
+from wbb.core.keyboard import ikb
 from wbb.utils.pastebin import paste
 
 callback = "log_paste"

+ 21 - 36
wbb/modules/misc.py

@@ -48,7 +48,8 @@ __HELP__ = """
 /tr [en] - Translate A Message
 /json [URL] - Get JSON Response From An API or Something.
 /arq - Statistics Of ARQ API.
-#RTFM - Check it lol
+/webss [URL] - Take A Screenshot Of A Webpage
+#RTFM - Tell noobs to read the manual
 """
 
 
@@ -136,7 +137,6 @@ async def random(_, message):
             '"/random" Needs An Argurment.' " Ex: `/random 5`"
         )
     length = message.text.split(None, 1)[1]
-
     try:
         if 1 < int(length) < 1000:
             alphabet = string.ascii_letters + string.digits
@@ -148,10 +148,9 @@ async def random(_, message):
             await message.reply_text("Specify A Length Between 1-1000")
     except ValueError:
         await message.reply_text(
-            "Strings Won't Work!, Pass A" + " Positive Integer Between 1-1000"
+            "Strings Won't Work!, Pass A Positive Integer Less Than 1000"
         )
 
-
 # Encrypt
 
 
@@ -218,21 +217,6 @@ async def cheat(_, message):
         await m.edit(str(e))
         print(str(e))
 
-
-# Weather
-
-
-@app.on_message(filters.command("weather") & ~filters.edited)
-@capture_err
-async def weather(_, message):
-    if len(message.command) != 2:
-        return await message.reply_text("/weather [city]")
-    city = message.text.split(None, 1)[1]
-    m = await message.reply_text("Fetching Data")
-    data = await fetch_text(f"https://wttr.in/{city}?mnTC0")
-    await m.edit(f"`{data}`")
-
-
 # Translate
 
 
@@ -262,35 +246,36 @@ async def tr(_, message):
 @app.on_message(filters.command("json") & ~filters.edited)
 @capture_err
 async def json_fetch(_, message):
-    global fetch_limit
     if len(message.command) != 2:
         return await message.reply_text("/json [URL]")
     url = message.text.split(None, 1)[1]
+    m = await message.reply_text("Fetching")
     try:
         data = await fetch(url)
         data = await json_prettify(data)
-        fetch_limit += 1
         if len(data) < 4090:
-            await message.reply_text(data)
+            await m.edit(data)
         else:
             link = await paste(data)
-            await message.reply_text(
+            await m.edit(
                 f"[OUTPUT_TOO_LONG]({link})", disable_web_page_preview=True
             )
     except Exception as e:
-        await message.reply_text(str(e))
-        print(str(e))
+        await m.edit(str(e))
 
 
-@app.on_message(filters.command("bun"))
-async def bunn(_, message):
-    if message.reply_to_message:
-        await message.reply_to_message.reply_sticker(
-            "CAACAgUAAx0CWIlO9AABARyRYBhyjKXFATVhu7AGQwip3TzSFiMAAuMBAAJ7usBUIu2xBtXTmuweBA"
-        )
-        return await app.send_message(message.chat.id, text="Eat Bun")
-    if not message.reply_to_message:
-        await message.reply_sticker(
-            "CAACAgUAAx0CWIlO9AABARyRYBhyjKXFATVhu7AGQwip3TzSFiMAAuMBAAJ7usBUIu2xBtXTmuweBA"
+@app.on_message(filters.command("webss"))
+@capture_err
+async def take_ss(_, message):
+    if len(message.command) != 2:
+        return await message.reply_text("Give A Url To Fetch Screenshot.")
+    url = message.text.split(None, 1)[1]
+    m = await message.reply_text("**Uploading**")
+    try:
+        await app.send_photo(
+            message.chat.id,
+            photo=f"https://webshot.amanoteam.com/print?q={url}",
         )
-        await app.send_message(message.chat.id, text="Eat Bun")
+    except Exception:
+        return await m.edit("No Such Website.")
+    await m.delete()

+ 0 - 172
wbb/modules/pipes.py

@@ -1,172 +0,0 @@
-"""
-MIT License
-
-Copyright (c) 2021 TheHamkerCat
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-"""
-import asyncio
-
-from pyrogram import filters
-from pyrogram.types import Message
-
-from wbb import BOT_ID, SUDOERS, USERBOT_ID, app, app2
-from wbb.core.decorators.errors import capture_err
-from wbb.utils.dbfunctions import (activate_pipe, deactivate_pipe,
-                                   is_pipe_active, show_pipes)
-from wbb.utils.filter_groups import pipes_group
-
-__MODULE__ = "Pipes"
-__HELP__ = """
-**THIS MODULE IS ONLY FOR DEVS**
-
-Use this module to create a pipe that will forward messages of one chat/channel to another.
-
-
-/activate_pipe [FROM_CHAT_ID] [TO_CHAT_ID] [BOT|USERBOT]
-
-Active a pipe.
-
-choose 'BOT' or 'USERBOT' according to your needs, this will decide
-which client will fetch the message from 'FROM_CHAT'.
-
-
-/deactivate_pipe [FROM_CHAT_ID] [TO_CHAT_ID]
-
-Deactivete a pipe.
-
-
-/show_pipes
-
-Show all the active pipes.
-"""
-pipes_list_bot = []
-pipes_list_userbot = []
-
-
-async def load_pipes():
-    print("[INFO]: LOADING PIPES")
-    global pipes_list_bot, pipes_list_userbot
-    pipes_list_bot = []
-    pipes_list_userbot = []
-    pipes = await show_pipes()
-    for pipe in pipes:
-        if pipe["fetcher"] == "bot":
-            pipes_list_bot.append(pipe)
-            continue
-        pipes_list_userbot.append(pipe)
-    print("[INFO]: LOADED PIPES")
-
-
-loop = asyncio.get_running_loop()
-loop.create_task(load_pipes())
-
-
-@app.on_message(~filters.me, group=pipes_group)
-@capture_err
-async def pipes_worker_bot(_, message: Message):
-    for pipe in pipes_list_bot:
-        if pipe["from_chat_id"] == message.chat.id:
-            await message.forward(pipe["to_chat_id"])
-
-
-@app2.on_message(~filters.me, group=pipes_group)
-@capture_err
-async def pipes_worker_userbot(_, message: Message):
-    for pipe in pipes_list_userbot:
-        if pipe["from_chat_id"] == message.chat.id:
-            if not message.text:
-                m, temp = await asyncio.gather(
-                    app.listen(USERBOT_ID), message.copy(BOT_ID)
-                )
-                caption = f"Forwarded from `{pipe['from_chat_id']}`"
-                caption = (
-                    f"{temp.caption}\n\n{caption}" if temp.caption else caption
-                )
-                await app.copy_message(
-                    pipe["to_chat_id"],
-                    USERBOT_ID,
-                    m.message_id,
-                    caption=caption,
-                )
-                await asyncio.sleep(10)
-                await temp.delete()
-                return
-            caption = f"Forwarded from `{pipe['from_chat_id']}`"
-            await app.send_message(
-                pipe["to_chat_id"], text=message.text + "\n\n" + caption
-            )
-
-
-@app.on_message(filters.command("activate_pipe") & filters.user(SUDOERS))
-@capture_err
-async def activate_pipe_func(_, message: Message):
-    if len(message.command) != 4:
-        await message.reply_text(
-            "**Usage:**\n/activate_pipe [FROM_CHAT_ID] [TO_CHAT_ID] [BOT|USERBOT]"
-        )
-        return
-    text = message.text.strip().split()
-    from_chat = int(text[1])
-    to_chat = int(text[2])
-    fetcher = text[3].lower()
-    if fetcher != "bot" and fetcher != "userbot":
-        await message.reply_text("Wrong fetcher, see help menu.")
-        return
-    if await is_pipe_active(from_chat, to_chat):
-        await message.reply_text("This pipe is already active.")
-        return
-    await activate_pipe(from_chat, to_chat, fetcher)
-    await load_pipes()
-    await message.reply_text("Activated pipe.")
-
-
-@app.on_message(filters.command("deactivate_pipe") & filters.user(SUDOERS))
-@capture_err
-async def deactivate_pipe_func(_, message: Message):
-    if len(message.command) != 3:
-        await message.reply_text(
-            "**Usage:**\n/deactivate_pipe [FROM_CHAT_ID] [TO_CHAT_ID]"
-        )
-        return
-    text = message.text.strip().split()
-    from_chat = int(text[1])
-    to_chat = int(text[2])
-    if not await is_pipe_active(from_chat, to_chat):
-        await message.reply_text("This pipe is already inactive.")
-        return
-    await deactivate_pipe(from_chat, to_chat)
-    await load_pipes()
-    await message.reply_text("Deactivated pipe.")
-
-
-@app.on_message(filters.command("pipes") & filters.user(SUDOERS))
-@capture_err
-async def show_pipes_func(_, message: Message):
-    pipes = pipes_list_bot + pipes_list_userbot
-    if not pipes:
-        await message.reply_text("No pipe is active.")
-        return
-    text = ""
-    for count, pipe in enumerate(pipes, 1):
-        text += (
-            f"**Pipe:** `{count}`\n**From:** `{pipe['from_chat_id']}`\n"
-            + f"**To:** `{pipe['to_chat_id']}`\n**Fetcher:** `{pipe['fetcher']}`\n\n"
-        )
-    await message.reply_text(text)

+ 1 - 2
wbb/modules/quotly.py

@@ -123,11 +123,10 @@ async def quotly_func(client, message: Message):
         await m.delete()
         sticker.close()
     except Exception as e:
-        await message.reply_text(
+        await m.edit(
             "Something wrong happened while quoting messages,"
             + " This error usually happens when there's a "
             + " message containing something other than text."
         )
-        await m.delete()
         e = format_exc()
         print(e)

+ 11 - 6
wbb/modules/reddit.py

@@ -36,9 +36,10 @@ async def reddit(_, message):
     if len(message.command) != 2:
         return await message.reply_text("/reddit needs an argument")
     subreddit = message.text.split(None, 1)[1]
+    m = await message.reply_text("Searching")
     reddit = await arq.reddit(subreddit)
     if not reddit.ok:
-        return await message.reply_text(reddit.result)
+        return await m.edit(reddit.result)
     reddit = reddit.result
     nsfw = reddit.nsfw
     sreddit = reddit.subreddit
@@ -46,9 +47,13 @@ async def reddit(_, message):
     image = reddit.url
     link = reddit.postLink
     if nsfw:
-        return await message.reply_text("NSFW RESULTS COULD NOT BE SHOWN.")
-    caption = f"""**Title:** `{title}`
+        return await m.edit("NSFW RESULTS COULD NOT BE SHOWN.")
+    caption = f"""
+**Title:** `{title}`
 **Subreddit:** {sreddit}
-**PostLink:** {link}
-"""
-    await message.reply_photo(photo=image, caption=caption)
+**PostLink:** {link}"""
+    try:
+        await message.reply_photo(photo=image, caption=caption)
+        await m.delete()
+    except Exception as e:
+        await m.edit(e.MESSAGE)

+ 1 - 1
wbb/modules/taglogger.py

@@ -53,7 +53,7 @@ async def sendLog(message: Message):
 """
     button = InlineKeyboard(row_width=1)
     button.add(InlineKeyboardButton(text="Check Action", url=message.link))
-    await app.send_message(LOG_GROUP_ID, text=msg, reply_markup=button)
+    await app.send_message(LOG_GROUP_ID, text=msg, reply_markup=button, disable_web_page_preview=True)
 
 
 @app2.on_message(

+ 22 - 15
wbb/modules/tts.py

@@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
 import traceback
+from asyncio import get_running_loop
 from io import BytesIO
 
 from googletrans import Translator
@@ -34,25 +35,31 @@ from wbb import app
 __MODULE__ = "TTS"
 __HELP__ = "/tts - Convert Text To Speech."
 
+def convert(text):
+    audio = BytesIO()
+    i = Translator().translate(text, dest="en")
+    lang = i.src
+    tts = gTTS(text, lang=lang)
+    audio.name = lang + ".mp3"
+    tts.write_to_fp(audio)
+    return audio
+
 
 @app.on_message(filters.command("tts"))
 async def text_to_speech(_, message: Message):
+    if not message.reply_to_message:
+        return await message.reply_text("Reply to some text ffs.")
+    if not message.reply_to_message.text:
+        return await message.reply_text("Reply to some text ffs.")
+    m = await message.reply_text("Processing")
+    text = message.reply_to_message.text
     try:
-        if message.reply_to_message:
-            if message.reply_to_message.text:
-                m = await message.reply_text("Processing")
-                audio = BytesIO()
-                text = message.reply_to_message.text
-                i = Translator().translate(text, dest="en")
-                lang = i.src
-                tts = gTTS(text, lang=lang)
-                audio.name = lang + ".mp3"
-                tts.write_to_fp(audio)
-                await m.delete()
-                await message.reply_audio(audio)
-                return audio.close()
-        await message.reply_text("Reply to some text ffs.")
+        loop = get_running_loop()
+        audio = await loop.run_in_executor(None, convert, text)
+        await message.reply_audio(audio)
+        await m.delete()
+        audio.close()
     except Exception as e:
-        await message.reply_text(e)
+        await m.edit(e)
         e = traceback.format_exc()
         print(e)

+ 0 - 21
wbb/modules/webss.py

@@ -27,25 +27,4 @@ from wbb import app
 from wbb.core.decorators.errors import capture_err
 
 __MODULE__ = "WebSS"
-__HELP__ = "/webss | .webss [URL] - Take A Screenshot Of A Webpage"
 
-
-@app.on_message(filters.command("webss"))
-@capture_err
-async def take_ss(_, message):
-    try:
-        if len(message.command) != 2:
-            return await message.reply_text("Give A Url To Fetch Screenshot.")
-        url = message.text.split(None, 1)[1]
-        m = await message.reply_text("**Taking Screenshot**")
-        await m.edit("**Uploading**")
-        try:
-            await app.send_photo(
-                message.chat.id,
-                photo=f"https://webshot.amanoteam.com/print?q={url}",
-            )
-        except TypeError:
-            return await m.edit("No Such Website.")
-        await m.delete()
-    except Exception as e:
-        await message.reply_text(str(e))

+ 0 - 3
wbb/modules/ytdl.py

@@ -68,7 +68,6 @@ async def ytdl_func(_, message):
         VIDEO_DATA[data] = {
             "url": url,
             "title": title,
-            "size": size,
             "quality": quality,
             "duration": duration,
             "format": format,
@@ -99,12 +98,10 @@ async def ytdlCallback(_, cq):
         title = data["title"]
         duration = data["duration"]
         format = data["format"]
-        size = data["size"]
         thumbnail = data["thumbnail"]
         cc = data["cc"]
         caption = f"""
 **Title:** {title}
-**Size:** {size}
 **Format:** {format}
 **Duration:** {await timeFormat(duration)}
 **CC:** {cc}

+ 58 - 4
wbb/utils/functions.py

@@ -24,8 +24,10 @@ SOFTWARE.
 import codecs
 import pickle
 from asyncio import gather, get_running_loop
+from io import BytesIO
 from math import atan2, cos, radians, sin, sqrt
 from random import randint
+from re import findall
 
 import aiofiles
 import aiohttp
@@ -128,10 +130,8 @@ async def get_http_status_code(url: str) -> int:
 async def make_carbon(code):
     url = "https://carbonara.vercel.app/api/cook"
     async with aiosession.post(url, json={"code": code}) as resp:
-        data = await resp.read()
-    image = f"{randint(100, 10000)}.png"
-    async with aiofiles.open(image, mode="wb") as f:
-        await f.write(data)
+        image = BytesIO(await resp.read())
+    image.name = "carbon.png"
     return image
 
 
@@ -171,3 +171,57 @@ async def calc_distance_from_ip(ip1: str, ip2: str) -> float:
     c = 2 * atan2(sqrt(a), sqrt(1 - a))
     distance = Radius_Earth * c
     return distance
+
+
+def get_urls_from_text(text: str) -> bool:
+    regex = r"""(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]
+                [.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(
+                \([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\
+                ()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""".strip()
+    return [x[0] for x in findall(regex, text)]
+
+
+async def extract_userid(message, text: str):
+    text = text.strip()
+    entities = message.entities
+    app = message._client
+    if len(entities) < 2:
+        return (await app.get_users(text)).id
+    entity = entities[1]
+    if entity.type == "mention":
+        return (await app.get_users(text)).id
+    if entity.type == "text_mention":
+        return entity.user.id
+    return None
+
+
+async def extract_user_and_reason(message):
+    args = message.text.strip().split()
+    text = message.text
+    user = None
+    reason = None
+    if message.reply_to_message:
+        reply = message.reply_to_message
+        # if reply to a message and no reason is given
+        if not reply.from_user:
+            return None, None
+        if len(args) < 2:
+            reason = None
+        else:
+            reason = text.split(None, 1)[1]
+        return reply.from_user.id, reason
+
+    # if not reply to a message and no reason is given
+    if len(args) == 2:
+        user = text.split(None, 1)[1]
+        return await extract_userid(message, user), None
+    # if reason is given
+    elif len(args) > 2:
+        user, reason = text.split(None, 2)[1:]
+        return await extract_userid(message, user), reason
+
+    return user, reason
+
+
+async def extract_user(message):
+    return (await extract_user_and_reason())[0]

+ 2 - 2
wbb/utils/json_prettify.py

@@ -42,10 +42,10 @@ async def json_prettify(data):
     output = ""
     try:
         for key, value in data.items():
-            output += f"**{key}:** `{value}`\n"
+            output += f"**{str(key).capitalize()}:** `{value}`\n"
     except Exception:
         for datas in data:
             for key, value in datas.items():
-                output += f"**{key}:** `{value}`\n"
+                output += f"**{str(key).capitalize()}:** `{value}`\n"
             output += "------------------------\n"
     return output