Forráskód Böngészése

Many updates

Removed gh_user, gh_repo, bitly and pypi from inline.

Removed .c, .go from userbot.py.

Added code executor in inline (supports 61 languages).

Sorted filters and notes alphabetically .

Implemented a back-button in Module help page.
TheHamkerCat 5 éve
szülő
commit
c803e844a9

+ 14 - 17
README.md

@@ -7,17 +7,15 @@
 </h3>
 
 <p align="center">
-    <a href="https://python.org"> <img src="http://forthebadge.com/images/badges/made-with-python.svg" alt="made-with-python"></a>
-    <a href="https://GitHub.com/TheHamkerCat"> <img src="http://ForTheBadge.com/images/badges/built-with-love.svg" alt="built-with-love"></a>
-</p>
-
-<p align="center">
+    <a href="https://python.org">
+        <img src="http://forthebadge.com/images/badges/made-with-python.svg" alt="made-with-python">
+    </a>
+    <a href="https://GitHub.com/TheHamkerCat">
+        <img src="http://ForTheBadge.com/images/badges/built-with-love.svg" alt="built-with-love">
+    </a> <br>
     <img src="https://img.shields.io/github/license/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="LICENSE">
     <img src="https://img.shields.io/github/contributors/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="Contributors">
-    <img src="https://img.shields.io/github/repo-size/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="Repository Size">
-</p>
-
-<p align="center">
+    <img src="https://img.shields.io/github/repo-size/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="Repository Size"> <br>
     <img src="https://img.shields.io/badge/python-3.9-green?style=for-the-badge&logo=appveyor" alt="Python Version">
     <img src="https://img.shields.io/github/issues/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="Issues">
     <img src="https://img.shields.io/github/forks/thehamkercat/WilliamButcherBot?style=for-the-badge&logo=appveyor" alt="Forks">
@@ -67,9 +65,12 @@ thehamkercat@arch:~$ cp sample_config.py config.py
 ```console
 thehamkercat@arch:~$ python3 -m wbb
 ```
-
-<h1 align="center"> 
-   ⇝ Run On Heroku ⇜
+<h1>
+    <p align="center">
+        <a href="https://heroku.com/deploy?template=https://github.com/thehamkercat/WilliamButcherBot">
+            <img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
+        </a>
+    </p>
 </h1>
 
 <h3 align="center"> 
@@ -83,10 +84,6 @@ thehamkercat@arch:~$ pip3 install pyrogram TgCrypto
 thehamkercat@arch:~$ python3 str_gen.py
 ```
 
-<p align="center">
-    <a href="https://heroku.com/deploy?template=https://github.com/thehamkercat/WilliamButcherBot"> <img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy"></a>
-</p>
-
 <h1 align="center"> 
    ⇝ Docker ⇜
 </h1>
@@ -133,4 +130,4 @@ async def some_function(_, message):
 
 <h3 align="center"> 
    And put that file in wbb/modules/, restart and test your bot.
-</h3>
+</h3>

+ 1 - 0
requirements.txt

@@ -23,3 +23,4 @@ wget
 python-dotenv
 feedparser
 pyromod
+fuzzysearch

+ 47 - 33
wbb/__main__.py

@@ -104,6 +104,42 @@ async def start_bot():
     await aiohttpsession.close()
 
 
+home_keyboard_pm = InlineKeyboardMarkup(
+    [
+        [
+            InlineKeyboardButton(
+                text="Commands ❓", callback_data="bot_commands"
+            ),
+            InlineKeyboardButton(
+                text="Repo 🛠",
+                url="https://github.com/thehamkercat/WilliamButcherBot",
+            ),
+        ],
+        [
+            InlineKeyboardButton(
+                text="System Stats 🖥",
+                callback_data="stats_callback",
+            ),
+            InlineKeyboardButton(
+                text="Support 👨", url="http://t.me/WBBSupport"
+            ),
+        ],
+        [
+            InlineKeyboardButton(
+                text="Add Me To Your Group 🎉",
+                url=f"http://t.me/{BOT_USERNAME}?startgroup=new",
+            )
+        ],
+    ]
+)
+
+home_text_pm = (
+    f"Hey there! My name is {BOT_NAME}. I can manage your "
+    + "group with lots of useful features, feel free to "
+    + "add me to your group."
+)
+
+
 @app.on_message(filters.command(["help", "start"]))
 async def help_command(_, message):
     if message.chat.type != "private":
@@ -130,41 +166,12 @@ async def help_command(_, message):
                 ],
             ]
         )
-        await message.reply(
+        return await message.reply(
             "Pm Me For More Details.", reply_markup=keyboard
         )
-        return
-    keyboard = InlineKeyboardMarkup(
-        [
-            [
-                InlineKeyboardButton(
-                    text="Commands ❓", callback_data="bot_commands"
-                ),
-                InlineKeyboardButton(
-                    text="Repo 🛠",
-                    url="https://github.com/thehamkercat/WilliamButcherBot",
-                ),
-            ],
-            [
-                InlineKeyboardButton(
-                    text="System Stats 🖥",
-                    callback_data="stats_callback",
-                ),
-                InlineKeyboardButton(
-                    text="Support 👨", url="http://t.me/WBBSupport"
-                ),
-            ],
-            [
-                InlineKeyboardButton(
-                    text="Add Me To Your Group 🎉",
-                    url=f"http://t.me/{BOT_USERNAME}?startgroup=new",
-                )
-            ],
-        ]
-    )
     await message.reply(
-        f"Hey there! My name is {BOT_NAME}. I can manage your group with lots of useful features, feel free to add me to your group.",
-        reply_markup=keyboard,
+        home_text_pm,
+        reply_markup=home_keyboard_pm,
     )
 
 
@@ -210,6 +217,7 @@ async def stats_callbacc(_, CallbackQuery):
 
 @app.on_callback_query(filters.regex(r"help_(.*?)"))
 async def help_button(client, query):
+    home_match = re.match(r"help_home\((.+?)\)", query.data)
     mod_match = re.match(r"help_module\((.+?)\)", query.data)
     prev_match = re.match(r"help_prev\((.+?)\)", query.data)
     next_match = re.match(r"help_next\((.+?)\)", query.data)
@@ -247,7 +255,13 @@ General command are:
             ),
             disable_web_page_preview=True,
         )
-
+    elif home_match:
+        await app.send_message(
+            query.from_user.id,
+            text=home_text_pm,
+            reply_markup=home_keyboard_pm,
+        )
+        await query.message.delete()
     elif prev_match:
         curr_page = int(prev_match.group(1))
         await query.message.edit(

+ 8 - 6
wbb/modules/filters.py

@@ -83,12 +83,14 @@ async def save_filters(_, message):
 async def get_filterss(_, message):
     _filters = await get_filters_names(message.chat.id)
     if not _filters:
-        await message.reply_text("**No filters in this chat.**")
-    else:
-        msg = f"List of filters in {message.chat.title}\n"
-        for _filter in _filters:
-            msg += f"**-** `{_filter}`\n"
-        await message.reply_text(msg)
+        return await message.reply_text(
+            "**No filters in this chat.**"
+        )
+    _filters.sort()
+    msg = f"List of filters in {message.chat.title}\n"
+    for _filter in _filters:
+        msg += f"**-** `{_filter}`\n"
+    await message.reply_text(msg)
 
 
 @app.on_message(

+ 0 - 1
wbb/modules/greetings.py

@@ -27,7 +27,6 @@ import os
 from datetime import datetime
 from random import shuffle
 
-from pykeyboard import InlineKeyboard
 from pyrogram import filters
 from pyrogram.errors.exceptions.bad_request_400 import (
     ChatAdminRequired, UserNotParticipant)

+ 6 - 4
wbb/modules/info.py

@@ -38,8 +38,9 @@ __HELP__ = """
 """
 
 
-async def get_user_info(user):
-    user = await app.get_users(user)
+async def get_user_info(user, already=False):
+    if not already:
+        user = await app.get_users(user)
     if not user.first_name:
         return ["Deleted account", None]
     user_id = user.id
@@ -65,8 +66,9 @@ async def get_user_info(user):
     return [caption, photo_id]
 
 
-async def get_chat_info(chat):
-    chat = await app.get_chat(chat)
+async def get_chat_info(chat, already=False):
+    if not already:
+        chat = await app.get_chat(chat)
     chat_id = chat.id
     username = chat.username
     title = chat.title

+ 4 - 70
wbb/modules/inline.py

@@ -91,19 +91,6 @@ async def inline_query_handler(client, query):
                 query.id,
                 results=answerss,
             )
-        elif text.split()[0] == "bitly":
-            if len(text.split()) < 2:
-                return await client.answer_inline_query(
-                    query.id,
-                    results=answers,
-                    switch_pm_text="Link Shortener | bitly [LINK]",
-                    switch_pm_parameter="inline",
-                )
-            tex = text.split(None, 1)[1].strip()
-            answerss = await shortify(tex)
-            await client.answer_inline_query(
-                query.id, results=answerss, cache_time=2
-            )
 
         elif text.split()[0] == "wall":
             if len(text.split()) < 2:
@@ -163,34 +150,6 @@ async def inline_query_handler(client, query):
                 query.id, results=answerss
             )
 
-        elif text.split()[0] == "gh_user":
-            if len(text.split()) < 2:
-                return await client.answer_inline_query(
-                    query.id,
-                    results=answers,
-                    switch_pm_text="Github User | gh_user [USERNAME/LINK]",
-                    switch_pm_parameter="inline",
-                )
-            tex = text.split(None, 1)[1].strip()
-            answerss = await github_user_func(answers, tex)
-            await client.answer_inline_query(
-                query.id, results=answerss, cache_time=2
-            )
-
-        elif text.split()[0] == "gh_repo":
-            if len(text.split()) < 2:
-                return await client.answer_inline_query(
-                    query.id,
-                    results=answers,
-                    switch_pm_text="Github Repo Search | [LINK]",
-                    switch_pm_parameter="inline",
-                )
-            tex = text.split(None, 1)[1].strip()
-            answerss = await github_repo_func(answers, tex)
-            await client.answer_inline_query(
-                query.id, results=answerss, cache_time=2
-            )
-
         elif text.split()[0] == "search":
             if len(text.split()) < 2:
                 return await client.answer_inline_query(
@@ -277,21 +236,7 @@ async def inline_query_handler(client, query):
                     switch_pm_parameter="inline",
                 )
             tex = text.split()[1].strip()
-            answerss = await user_info_inline_func(answers, tex)
-            await client.answer_inline_query(
-                query.id, results=answerss, cache_time=2
-            )
-
-        elif text.split()[0] == "chat_info":
-            if len(text.split()) < 2:
-                return await client.answer_inline_query(
-                    query.id,
-                    results=answers,
-                    switch_pm_text="Chat Info | chat_info [USERNAME|ID]",
-                    switch_pm_parameter="inline",
-                )
-            tex = text.split()[1].strip()
-            answerss = await chat_info_inline_func(answers, tex)
+            answerss = await info_inline_func(answers, tex)
             await client.answer_inline_query(
                 query.id, results=answerss, cache_time=2
             )
@@ -311,20 +256,6 @@ async def inline_query_handler(client, query):
                 query.id, results=answerss, cache_time=2
             )
 
-        elif text.split()[0] == "pypi":
-            if len(text.split()) < 2:
-                return await client.answer_inline_query(
-                    query.id,
-                    results=answers,
-                    switch_pm_text="Pypi Search | pypi [Package Name]",
-                    switch_pm_parameter="inline",
-                )
-            tex = text.split()[1].strip()
-            answerss = await pypiSearchFunc(answers, tex)
-            await client.answer_inline_query(
-                query.id, results=answerss, cache_time=2
-            )
-
         elif text.split()[0] == "image":
             if len(text.split()) < 2:
                 return await client.answer_inline_query(
@@ -340,6 +271,9 @@ async def inline_query_handler(client, query):
                 query.id, results=answerss, cache_time=3600
             )
 
+        elif text.split()[0] == "exec":
+            await execute_code(query)
+
     except Exception as e:
         e = traceback.format_exc()
         print(e, " InLine")

+ 0 - 1
wbb/modules/karma.py

@@ -21,7 +21,6 @@ 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 re
 
 from pyrogram import filters

+ 0 - 3
wbb/modules/music.py

@@ -27,11 +27,8 @@ import os
 from asyncio import get_running_loop
 from functools import partial
 from io import BytesIO
-from random import randint
 from urllib.parse import urlparse
 
-import aiofiles
-import aiohttp
 import ffmpeg
 import youtube_dl
 from pyrogram import filters

+ 6 - 6
wbb/modules/notes.py

@@ -82,12 +82,12 @@ async def get_notes(_, message):
     _notes = await get_note_names(message.chat.id)
 
     if not _notes:
-        await message.reply_text("**No notes in this chat.**")
-    else:
-        msg = f"List of notes in {message.chat.title}\n"
-        for note in _notes:
-            msg += f"**-** `{note}`\n"
-        await message.reply_text(msg)
+        return await message.reply_text("**No notes in this chat.**")
+    _notes.sort()
+    msg = f"List of notes in {message.chat.title}\n"
+    for note in _notes:
+        msg += f"**-** `{note}`\n"
+    await message.reply_text(msg)
 
 
 @app.on_message(

+ 0 - 1
wbb/modules/rss.py

@@ -1,5 +1,4 @@
 from asyncio import get_event_loop, sleep
-from time import time
 
 from pyrogram import filters
 from pyrogram.types import Message

+ 0 - 86
wbb/modules/userbot.py

@@ -14,7 +14,6 @@ from html import escape
 from inspect import getfullargspec
 from io import StringIO
 
-import aiofiles
 from pyrogram import filters
 from pyrogram.types import Message, ReplyKeyboardMarkup
 
@@ -214,88 +213,3 @@ def shell(cmd: list) -> tuple:
     stdout = stdout.decode() if stdout else None
     stderr = stderr.decode() if stderr else None
     return stdout, stderr
-
-
-""" C and CPP Eval """
-
-
-async def sendFile(message: Message, text: str):
-    file = "output.txt"
-    async with aiofiles.open(file, mode="w+") as f:
-        await f.write(text)
-    await message.reply_document(file)
-    os.remove(file)
-
-
-@app2.on_message(
-    filters.command(["c", "cpp"], prefixes=USERBOT_PREFIX)
-    & ~filters.edited
-    & ~filters.via_bot
-    & filters.user(SUDOERS)
-)
-async def c_cpp_eval(_, message: Message):
-    if len(message.command) < 2:
-        return await message.edit("Write Some Code..")
-
-    if message.reply_to_message:
-        r = message.reply_to_message
-        if r.reply_markup:
-            if isinstance(r.reply_markup, ReplyKeyboardMarkup):
-                return await message.edit("INSECURE!")
-
-    code = message.text.split(None, 1)[1]
-    file = "exec.c"
-    compiler = "g++"
-    out_file = "exec"
-    cmdCompile = [compiler, "-g", file, "-o", out_file]
-    cmdRun = [f"./{out_file}"]
-    async with aiofiles.open(file, mode="w+") as f:
-        await f.write(code)
-    out, err = shell(cmdCompile)
-    os.remove(file)
-    if err:
-        text = f"**INPUT:**\n```{escape(code)}```\n\n**COMPILE-TIME ERROR:**```{escape(err)}```"
-        if len(text) > 4090:
-            return await sendFile(message, text)
-        return await edit_or_reply(message, text=text)
-    out, err = shell(cmdRun)
-    os.remove(out_file)
-    err = f"**RUNTIME ERROR:**\n```{escape(err)}```" if err else None
-    out = f"**OUTPUT:**\n```{escape(out)}```" if out else None
-    text = (
-        f"**INPUT:**\n```{escape(code)}```\n\n{out if out else err}"
-    )
-    if len(text) > 4090:
-        return await sendFile(message, text)
-    await edit_or_reply(message, text=text)
-
-
-@app2.on_message(
-    filters.command("go", prefixes=USERBOT_PREFIX)
-    & ~filters.edited
-    & ~filters.via_bot
-    & filters.user(SUDOERS)
-)
-async def goval(_, message: Message):
-    if len(message.command) < 2:
-        return await message.edit("Write Some Code...")
-
-    if message.reply_to_message:
-        r = message.reply_to_message
-        if r.reply_markup:
-            if isinstance(r.reply_markup, ReplyKeyboardMarkup):
-                return await message.edit("INSECURE!")
-
-    code = message.text.split(None, 1)[1]
-    file = "main.go"
-    cmdRun = ["go", "run", file]
-    async with aiofiles.open(file, mode="w+") as f:
-        await f.write(code)
-    stdout, stderr = shell(cmdRun)
-    os.remove(file)
-    out = stdout or stderr or None
-    out = f"**OUTPUT:**\n```{escape(out)}```"
-    text = f"**INPUT:**\n```{escape(code)}```\n\n{out}"
-    if len(text) > 4090:
-        return await sendFile(message, text)
-    await edit_or_reply(message, text=text)

+ 107 - 202
wbb/utils/inlinefuncs.py

@@ -25,10 +25,12 @@ import asyncio
 import json
 import os
 import sys
+from html import escape
 from re import sub as re_sub
 from sys import version as pyver
 from time import ctime, time
 
+from fuzzysearch import find_near_matches
 from motor import version as mongover
 from pykeyboard import InlineKeyboard
 from pyrogram import __version__ as pyrover
@@ -51,28 +53,23 @@ from wbb.utils.http import get
 from wbb.utils.pastebin import paste
 
 keywords_list = [
-    "alive",
+    "image",
+    "wall",
+    "tmdb",
+    "lyrics",
+    "exec",
+    "speedtest",
+    "search",
     "ping",
     "tr",
     "ud",
-    "google",
-    "bitly",
-    "wall",
     "yt",
+    "info",
+    "google",
     "torrent",
-    "lyrics",
     "wiki",
-    "speedtest",
     "music",
-    "gh_repo",
-    "gh_user",
-    "search",
     "ytmusic",
-    "info",
-    "chat_info",
-    "tmdb",
-    "pypi",
-    "image",
 ]
 
 
@@ -271,35 +268,6 @@ async def wall_func(answers, text):
     return answers
 
 
-# Used my api key here, don't fuck it
-async def shortify(url):
-    if "." not in url:
-        return
-    header = {
-        "Authorization": "Bearer ad39983fa42d0b19e4534f33671629a4940298dc",
-        "Content-Type": "application/json",
-    }
-    payload = {"long_url": f"{url}"}
-    payload = json.dumps(payload)
-    async with aiohttpsession.post(
-        "https://api-ssl.bitly.com/v4/shorten",
-        headers=header,
-        data=payload,
-    ) as resp:
-        data = await resp.json()
-    msg = data["link"]
-    a = []
-    b = InlineQueryResultArticle(
-        title="Link Shortened!",
-        description=data["link"],
-        input_message_content=InputTextMessageContent(
-            msg, disable_web_page_preview=True
-        ),
-    )
-    a.append(b)
-    return a
-
-
 async def torrent_func(answers, text):
     results = await arq.torrent(text)
     if not results.ok:
@@ -416,83 +384,6 @@ async def lyrics_func(answers, text):
     return answers
 
 
-async def github_user_func(answers, text):
-    URL = f"https://api.github.com/users/{text}"
-    result = await get(URL)
-    buttons = InlineKeyboard(row_width=1)
-    buttons.add(
-        InlineKeyboardButton(
-            text="Open On Github", url=f"https://github.com/{text}"
-        )
-    )
-    caption = f"""
-**Info Of {result['name']}**
-**Username:** `{text}`
-**Bio:** `{result['bio']}`
-**Profile Link:** [Here]({result['html_url']})
-**Company:** `{result['company']}`
-**Created On:** `{result['created_at']}`
-**Repositories:** `{result['public_repos']}`
-**Blog:** `{result['blog']}`
-**Location:** `{result['location']}`
-**Followers:** `{result['followers']}`
-**Following:** `{result['following']}`"""
-    answers.append(
-        InlineQueryResultPhoto(
-            photo_url=result["avatar_url"],
-            caption=caption,
-            reply_markup=buttons,
-        )
-    )
-    return answers
-
-
-async def github_repo_func(answers, text):
-    text = text.replace("https://github.com/", "")
-    text = text.replace("http://github.com/", "")
-    if text[-1] == "/":
-        text = text[0:-1]
-    URL = f"https://api.github.com/repos/{text}"
-    URL2 = f"https://api.github.com/repos/{text}/contributors"
-    results = await asyncio.gather(get(URL), get(URL2))
-    r = results[0]
-    r1 = results[1]
-    commits = 0
-    for developer in r1:
-        commits += developer["contributions"]
-    buttons = InlineKeyboard(row_width=1)
-    buttons.add(
-        InlineKeyboardButton(
-            "Open On Github", url=f"https://github.com/{text}"
-        )
-    )
-    caption = f"""
-**Info Of {r['full_name']}**
-**Stars:** `{r['stargazers_count']}`
-**Watchers:** `{r['watchers_count']}`
-**Forks:** `{r['forks_count']}`
-**Commits:** `{commits}`
-**Is Fork:** `{r['fork']}`
-**Language:** `{r['language']}`
-**Contributors:** `{len(r1)}`
-**License:** `{r['license']['name'] if r['license'] else None}`
-**Repo Owner:** [{r['owner']['login']}]({r['owner']['html_url']})
-**Created On:** `{r['created_at']}`
-**Homepage:** {r['homepage']}
-**Description:** __{r['description']}__"""
-    answers.append(
-        InlineQueryResultArticle(
-            title="Found Repo",
-            description=text,
-            reply_markup=buttons,
-            input_message_content=InputTextMessageContent(
-                caption, disable_web_page_preview=True
-            ),
-        )
-    )
-    return answers
-
-
 async def tg_search_func(answers, text, user_id):
     if user_id not in SUDOERS:
         msg = "**ERROR**\n__THIS FEATURE IS ONLY FOR SUDO USERS__"
@@ -781,35 +672,28 @@ async def yt_music_func(answers, url):
     return answers
 
 
-async def user_info_inline_func(answers, user):
+async def info_inline_func(answers, peer):
+    not_found = InlineQueryResultArticle(
+        title="PEER NOT FOUND",
+        input_message_content=InputTextMessageContent(
+            "PEER NOT FOUND"
+        ),
+    )
     try:
-        caption, _ = await get_user_info(user)
+        user = await app.get_users(peer)
+        caption, _ = await get_user_info(user, True)
+    except IndexError:
+        try:
+            chat = await app.get_chat(peer)
+            caption, _ = await get_chat_info(chat, True)
+        except Exception:
+            return [not_found]
     except Exception:
-        answers.append(
-            InlineQueryResultArticle(
-                title="USER NOT FOUND",
-                input_message_content=InputTextMessageContent(
-                    "USER NOT FOUND"
-                ),
-            )
-        )
-        return answers
-    answers.append(
-        InlineQueryResultArticle(
-            title="Found User.",
-            input_message_content=InputTextMessageContent(
-                caption, disable_web_page_preview=True
-            ),
-        )
-    )
-    return answers
-
+        return [not_found]
 
-async def chat_info_inline_func(answers, chat):
-    caption, photo_id = await get_chat_info(chat)
     answers.append(
         InlineQueryResultArticle(
-            title="Found Chat.",
+            title="Found Peer.",
             input_message_content=InputTextMessageContent(
                 caption, disable_web_page_preview=True
             ),
@@ -871,64 +755,6 @@ async def tmdb_func(answers, query):
     return answers
 
 
-async def pypiSearchFunc(answers: list, query: str) -> list:
-    result = await arq.pypi(query)
-    if not result.ok:
-        answers.append(
-            InlineQueryResultArticle(
-                title="No Such Package",
-                description=result.result,
-                input_message_content=InputTextMessageContent(
-                    result.result
-                ),
-            )
-        )
-        return answers
-    result = result.result
-    pURLS = [
-        f"**{key}**: {value}"
-        for key, value in result.projectURLS.items()
-    ]
-    pURLS = ("\n" + "\n".join(pURLS)) if pURLS else None
-    caption = f"""
-**Name:** {result.name}
-**Version:** {result.version}
-**License:** {result.license}
-**Description:** {result.description}
-**Size:** {result.size}
-**Last Update:** {result.uploadTime}
-**Author:** {result.author}
-**Author's Email:** {result.authorEmail}
-**Requirements:** {(f'`{" | ".join(result.requirements)}`') if result.requirements else None}
-**Minimum Python Version:** {result.minPyVersion}
-**Homepage:** {result.homepage}
-**Bug Tracker:** {result.bugTrackURL}
-**Docs Url:** {result.docsURL}
-**Pypi Url:** {result.pypiURL}
-**Releases:** {result.releaseURL}
-**Project Urls:** ->{pURLS}
-"""
-    button = InlineKeyboard(row_width=2)
-    button.add(
-        InlineKeyboardButton(text="Open Page", url=result.pypiURL),
-        InlineKeyboardButton(
-            text="Search Again",
-            switch_inline_query_current_chat="pypi",
-        ),
-    )
-    answers.append(
-        InlineQueryResultArticle(
-            title=f"{result.name}  |  {result.version}",
-            description=result.description,
-            input_message_content=InputTextMessageContent(
-                caption, disable_web_page_preview=True
-            ),
-            reply_markup=button,
-        )
-    )
-    return answers
-
-
 async def image_func(answers, query):
     results = await arq.image(query)
     if not results.ok:
@@ -960,3 +786,82 @@ async def image_func(answers, query):
             )
         )
     return answers
+
+
+async def execute_code(query):
+    text = query.query.strip()
+    offset = int((query.offset or 0))
+    answers = []
+    languages = (await arq.execute()).result
+    if len(text.split()) == 1:
+        answers = [
+            InlineQueryResultArticle(
+                title=lang,
+                input_message_content=InputTextMessageContent(lang),
+            )
+            for lang in languages
+        ][offset : offset + 25]
+        await query.answer(
+            next_offset=str(offset + 25),
+            results=answers,
+            cache_time=1,
+        )
+    elif len(text.split()) == 2:
+        text = text.split()[1].strip()
+        languages = list(
+            filter(
+                lambda x: find_near_matches(text, x, max_l_dist=1),
+                languages,
+            )
+        )
+        answers.extend(
+            [
+                InlineQueryResultArticle(
+                    title=lang,
+                    input_message_content=InputTextMessageContent(
+                        lang
+                    ),
+                )
+                for lang in languages
+            ][:49]
+        )
+    else:
+        lang = text.split()[1]
+        code = text.split(None, 2)[2]
+        response = await arq.execute(lang, code)
+        if not response.ok:
+            answers.append(
+                InlineQueryResultArticle(
+                    title="Error",
+                    input_message_content=InputTextMessageContent(
+                        response.result
+                    ),
+                )
+            )
+        else:
+            res = response.result
+            stdout, stderr = escape(res.stdout), escape(res.stderr)
+            output = stdout or stderr
+            out = (
+                "STDOUT"
+                if stdout
+                else ("STDERR" if stderr else "No output")
+            )
+
+            msg = f"""
+**{lang.capitalize()}:** 
+```{code}```
+
+**{out}:**
+```{output}```
+            """
+            answers.append(
+                InlineQueryResultArticle(
+                    title="Executed",
+                    description=output[:20],
+                    input_message_content=InputTextMessageContent(
+                        msg
+                    ),
+                )
+            )
+    await query.answer(results=answers, cache_time=1)

+ 6 - 0
wbb/utils/misc.py

@@ -93,6 +93,12 @@ def paginate_modules(page_n, module_dict, prefix, chat=None):
                         prefix, modulo_page
                     ),
                 ),
+                EqInlineKeyboardButton(
+                    "Back",
+                    callback_data="{}_home({})".format(
+                        prefix, modulo_page
+                    ),
+                ),
                 EqInlineKeyboardButton(
                     ">",
                     callback_data="{}_next({})".format(