ポキ 5 лет назад
Родитель
Сommit
6bf84062b9

+ 129 - 5
.gitignore

@@ -1,5 +1,129 @@
-config.ini
-WilliamButcher.session
-wbb/WilliamButcher.session
-wbb/config.ini
-wbb/__pycache__
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+*.ini
+*.pyc
+*.session
+*.session-journal

+ 4 - 10
wbb/__init__.py

@@ -1,6 +1,7 @@
 from pyrogram import Client
 from configparser import ConfigParser
 import logging
+import time
 import os
 
 
@@ -30,18 +31,11 @@ log = logging.getLogger()
 
 config = ConfigParser()
 config.read("config.ini")
-OWNER_ID = config.get("admin", "owner_id")
+OWNER_ID = int(config.get("admin", "owner_id"))
 Command = config.get("prefix", "prefixes").split()
 MOD_LOAD = config.get("mods", "load_modules").split()
 MOD_NOLOAD = config.get("mods", "noload_modules").split()
+bot_start_time = time.time()
 
 
-app = Client(
-    ":memory:"
-)
-
-
-
-
-
-
+app = Client(":memory:")

+ 10 - 13
wbb/__main__.py

@@ -11,8 +11,10 @@ import uvloop
 
 loop = asyncio.get_event_loop()
 
+
 HELPABLE = {}
 
+
 async def start_bot():
     await app.start()
     await get_info(app)
@@ -53,9 +55,7 @@ async def main_bot():
         if message.chat.type != "private":
             await message.reply("Message me Privately *winks*")
             return
-        await message.reply(
-            "Hi, try /help"
-        )
+        await message.reply("Hi, try /help")
 
     @app.on_message(cust_filter.command("help"))
     async def help_command(_, message):
@@ -103,20 +103,17 @@ async def main_bot():
 
         if mod_match:
             module = mod_match.group(1)
-            text = "{} **{}**:\n".format(
-                "Here is the help for", HELPABLE[module].__MODULE__
-            ) + HELPABLE[module].__HELP__
+            text = (
+                "{} **{}**:\n".format(
+                    "Here is the help for", HELPABLE[module].__MODULE__
+                )
+                + HELPABLE[module].__HELP__
+            )
 
             await q.message.edit(
                 text=text,
                 reply_markup=InlineKeyboardMarkup(
-                    [
-                        [
-                            InlineKeyboardButton(
-                                "back", callback_data="help_back"
-                            )
-                        ]
-                    ]
+                    [[InlineKeyboardButton("back", callback_data="help_back")]]
                 ),
                 disable_web_page_preview=True,
             )

+ 42 - 59
wbb/logs/error.log

@@ -1,59 +1,42 @@
-PEAK OF LOG FILE] __init__.py:42 INFO: Modules loaded: ['commit', 'greetings', 'ping', 'stats']
-[12-16 14:16.948] auth.py:81 INFO: Start creating a new auth key on DC2
-[12-16 14:16.948] connection.py:54 INFO: Connecting...
-[12-16 14:16.181] connection.py:65 INFO: Connected! Production DC2 - IPv4 - TCPAbridgedO
-[12-16 14:17.623] auth.py:248 INFO: Done auth key exchange: DhGenOk
-[12-16 14:17.624] connection.py:74 INFO: Disconnected
-[12-16 14:17.627] connection.py:54 INFO: Connecting...
-[12-16 14:17.862] connection.py:65 INFO: Connected! Production DC2 - IPv4 - TCPAbridgedO
-[12-16 14:17.862] session.py:345 INFO: NetworkTask started
-[12-16 14:17.382] msg_id.py:45 INFO: Time synced: 2020-12-16 09:17:01.268164 UTC
-[12-16 14:17.622] session.py:314 INFO: NextSaltTask started
-[12-16 14:17.623] session.py:326 INFO: Next salt in 44m 58s (2020-12-16 15:02:00)
-[12-16 14:17.943] session.py:168 INFO: Session initialized: Layer 117
-[12-16 14:17.943] session.py:169 INFO: Device: CPython 3.7.3 - Pyrogram 1.0.7
-[12-16 14:17.943] session.py:170 INFO: System: Linux 5.4.70-amd64-desktop (EN)
-[12-16 14:17.943] session.py:185 INFO: Session started
-[12-16 14:17.944] session.py:292 INFO: PingTask started
-[12-16 14:17.212] session.py:311 INFO: PingTask stopped
-[12-16 14:17.212] session.py:342 INFO: NextSaltTask stopped
-[12-16 14:17.212] connection.py:74 INFO: Disconnected
-[12-16 14:17.213] session.py:361 INFO: NetworkTask stopped
-[12-16 14:17.213] session.py:216 INFO: Session stopped
-[12-16 14:17.215] auth.py:81 INFO: Start creating a new auth key on DC5
-[12-16 14:17.215] connection.py:54 INFO: Connecting...
-[12-16 14:17.272] connection.py:65 INFO: Connected! Production DC5 - IPv4 - TCPAbridgedO
-[12-16 14:17.922] auth.py:248 INFO: Done auth key exchange: DhGenOk
-[12-16 14:17.922] connection.py:74 INFO: Disconnected
-[12-16 14:17.924] connection.py:54 INFO: Connecting...
-[12-16 14:17.982] connection.py:65 INFO: Connected! Production DC5 - IPv4 - TCPAbridgedO
-[12-16 14:17.982] session.py:345 INFO: NetworkTask started
-[12-16 14:17.242] session.py:314 INFO: NextSaltTask started
-[12-16 14:17.243] session.py:326 INFO: Next salt in 44m 59s (2020-12-16 15:02:02)
-[12-16 14:17.336] session.py:168 INFO: Session initialized: Layer 117
-[12-16 14:17.337] session.py:169 INFO: Device: CPython 3.7.3 - Pyrogram 1.0.7
-[12-16 14:17.337] session.py:170 INFO: System: Linux 5.4.70-amd64-desktop (EN)
-[12-16 14:17.337] session.py:185 INFO: Session started
-[12-16 14:17.337] session.py:292 INFO: PingTask started
-[12-16 14:17.512] dispatcher.py:122 INFO: Started 8 HandlerTasks
-[12-16 14:17.513] syncer.py:88 INFO: Synced ":memory:" in 0.695229 ms
-[12-16 14:17.514] syncer.py:88 INFO: Synced ":memory:" in 0.599384 ms
-[12-16 14:17.517] syncer.py:88 INFO: Synced ":memory:" in 0.4282 ms
-[12-16 14:18.518] syncer.py:88 INFO: Synced ":memory:" in 0.440359 ms
-[12-16 14:18.520] syncer.py:88 INFO: Synced ":memory:" in 0.711679 ms
-[12-16 14:18.522] syncer.py:88 INFO: Synced ":memory:" in 0.425577 ms
-[12-16 14:19.525] syncer.py:88 INFO: Synced ":memory:" in 0.70262 ms
-[12-16 14:19.526] syncer.py:88 INFO: Synced ":memory:" in 0.418901 ms
-[12-16 14:19.527] syncer.py:88 INFO: Synced ":memory:" in 0.478506 ms
-[12-16 14:20.529] syncer.py:88 INFO: Synced ":memory:" in 0.4282 ms
-[12-16 14:20.530] syncer.py:88 INFO: Synced ":memory:" in 0.533581 ms
-[12-16 14:20.532] syncer.py:88 INFO: Synced ":memory:" in 0.680923 ms
-[12-16 14:21.533] syncer.py:88 INFO: Synced ":memory:" in 0.426531 ms
-[12-16 14:21.535] syncer.py:88 INFO: Synced ":memory:" in 0.423193 ms
-[12-16 14:21.536] syncer.py:88 INFO: Synced ":memory:" in 0.436306 ms
-[12-16 14:22.537] syncer.py:88 INFO: Synced ":memory:" in 0.441074 ms
-[12-16 14:22.539] syncer.py:88 INFO: Synced ":memory:" in 0.504732 ms
-[12-16 14:22.541] syncer.py:88 INFO: Synced ":memory:" in 0.596285 ms
-[12-16 14:23.542] syncer.py:88 INFO: Synced ":memory:" in 0.424623 ms
-[12-16 14:23.544] syncer.py:88 INFO: Synced ":memory:" in 0.546932 ms
-[12-16 14:23.970] idle.py:71 INFO: Stop signal received (2). Exiting...
+PEAK OF LOG FILE] __init__.py:44 INFO: Modules loaded: ['commit', 'greetings', 'log', 'ping', 'stats']
+[12-16 19:12.134] auth.py:81 INFO: Start creating a new auth key on DC2
+[12-16 19:12.134] connection.py:54 INFO: Connecting...
+[12-16 19:12.365] connection.py:65 INFO: Connected! Production DC2 - IPv4 - TCPAbridgedO
+[12-16 19:12.733] auth.py:248 INFO: Done auth key exchange: DhGenOk
+[12-16 19:12.734] connection.py:74 INFO: Disconnected
+[12-16 19:12.736] connection.py:54 INFO: Connecting...
+[12-16 19:12.965] connection.py:65 INFO: Connected! Production DC2 - IPv4 - TCPAbridgedO
+[12-16 19:12.965] session.py:345 INFO: NetworkTask started
+[12-16 19:12.476] msg_id.py:45 INFO: Time synced: 2020-12-16 14:12:53.349668 UTC
+[12-16 19:12.707] session.py:314 INFO: NextSaltTask started
+[12-16 19:12.707] session.py:326 INFO: Next salt in 44m 58s (2020-12-16 19:57:52)
+[12-16 19:12.966] session.py:168 INFO: Session initialized: Layer 117
+[12-16 19:12.967] session.py:169 INFO: Device: CPython 3.7.3 - Pyrogram 1.0.7
+[12-16 19:12.967] session.py:170 INFO: System: Linux 5.4.70-amd64-desktop (EN)
+[12-16 19:12.967] session.py:185 INFO: Session started
+[12-16 19:12.968] session.py:292 INFO: PingTask started
+[12-16 19:12.216] session.py:311 INFO: PingTask stopped
+[12-16 19:12.216] session.py:342 INFO: NextSaltTask stopped
+[12-16 19:12.216] connection.py:74 INFO: Disconnected
+[12-16 19:12.216] session.py:361 INFO: NetworkTask stopped
+[12-16 19:12.216] session.py:216 INFO: Session stopped
+[12-16 19:12.218] auth.py:81 INFO: Start creating a new auth key on DC5
+[12-16 19:12.218] connection.py:54 INFO: Connecting...
+[12-16 19:12.273] connection.py:65 INFO: Connected! Production DC5 - IPv4 - TCPAbridgedO
+[12-16 19:12.996] auth.py:248 INFO: Done auth key exchange: DhGenOk
+[12-16 19:12.996] connection.py:74 INFO: Disconnected
+[12-16 19:12.998] connection.py:54 INFO: Connecting...
+[12-16 19:12.095] connection.py:65 INFO: Connected! Production DC5 - IPv4 - TCPAbridgedO
+[12-16 19:12.096] session.py:345 INFO: NetworkTask started
+[12-16 19:12.386] session.py:314 INFO: NextSaltTask started
+[12-16 19:12.386] session.py:326 INFO: Next salt in 44m 59s (2020-12-16 19:57:54)
+[12-16 19:12.506] session.py:168 INFO: Session initialized: Layer 117
+[12-16 19:12.506] session.py:169 INFO: Device: CPython 3.7.3 - Pyrogram 1.0.7
+[12-16 19:12.506] session.py:170 INFO: System: Linux 5.4.70-amd64-desktop (EN)
+[12-16 19:12.506] session.py:185 INFO: Session started
+[12-16 19:12.506] session.py:292 INFO: PingTask started
+[12-16 19:12.675] dispatcher.py:122 INFO: Started 8 HandlerTasks
+[12-16 19:12.676] syncer.py:88 INFO: Synced ":memory:" in 0.665426 ms
+[12-16 19:13.677] syncer.py:88 INFO: Synced ":memory:" in 0.443935 ms
+[12-16 19:13.679] syncer.py:88 INFO: Synced ":memory:" in 0.419617 ms
+[12-16 19:13.530] idle.py:71 INFO: Stop signal received (2). Exiting...

+ 3 - 1
wbb/modules/__init__.py

@@ -1,9 +1,11 @@
 import importlib
 from wbb import MOD_LOAD, MOD_NOLOAD, log
 
+
 def __list_all_modules():
     from os.path import dirname, basename, isfile
     import glob
+
     # This generates a list of modules in this folder for the * in __main__ to work.
     mod_paths = glob.glob(dirname(__file__) + "/*.py")
     all_modules = [
@@ -40,4 +42,4 @@ def __list_all_modules():
 importlib.import_module("wbb.modules.__main__")
 ALL_MODULES = sorted(__list_all_modules())
 log.info("Modules loaded: %s", str(ALL_MODULES))
-__all__ = ALL_MODULES + ["ALL_MODULES"]
+__all__ = ALL_MODULES + ["ALL_MODULES"]

BIN
wbb/modules/__pycache__/__init__.cpython-37.pyc


BIN
wbb/modules/__pycache__/__main__.cpython-37.pyc


BIN
wbb/modules/__pycache__/commit.cpython-37.pyc


BIN
wbb/modules/__pycache__/greetings.cpython-37.pyc


BIN
wbb/modules/__pycache__/help.cpython-37.pyc


BIN
wbb/modules/__pycache__/ping.cpython-37.pyc


BIN
wbb/modules/__pycache__/stats.cpython-37.pyc


+ 1 - 1
wbb/modules/commit.py

@@ -8,4 +8,4 @@ __HELP__ = "A Fun little module, try /commit uwu"
 
 @app.on_message(cust_filter.command(commands=(["commit"])))
 async def commit(client, message):
-    await message.reply_text(random_line('wbb/commit.txt'))
+    await message.reply_text(random_line("wbb/commit.txt"))

+ 3 - 2
wbb/modules/greetings.py

@@ -4,10 +4,11 @@ from pyrogram import filters, emoji
 __MODULE__ = "Greetings"
 __HELP__ = "Welcomes Users to the Group"
 
-MESSAGE = "{} Welcome {}!" 
+MESSAGE = "{} Welcome {}!"
+
 
 @app.on_message(filters.new_chat_members)
 async def welcome(client, message):
     new_members = [i.mention for i in message.new_chat_members]
     text = MESSAGE.format(emoji.CROWN, ", ".join(new_members))
-    await message.reply_text(text, disable_web_page_preview=True)
+    await message.reply_text(text, disable_web_page_preview=True)

+ 3 - 4
wbb/modules/log.py

@@ -3,6 +3,7 @@ import re
 from wbb.utils import cust_filter, nekobin
 from wbb import app, OWNER_ID
 
+
 @app.on_message(filters.user(OWNER_ID) & cust_filter.command("log"))
 async def logs_chat(client, message):
     keyb = types.InlineKeyboardMarkup(
@@ -35,10 +36,8 @@ async def paste_log_neko(client, query):
         keyb = types.InlineKeyboardMarkup(
             [[types.InlineKeyboardButton("pasted on nekobin", url=f"{data}")]]
         )
-        await query.message.edit_caption(
-            "Successfully Nekofied", reply_markup=keyb
-        )
+        await query.message.edit_caption("Successfully Nekofied", reply_markup=keyb)
     else:
         await client.answer_callback_query(
             query.id, "Sike its not for you!", show_alert=True
-        )
+        )

+ 3 - 2
wbb/modules/ping.py

@@ -5,9 +5,10 @@ from wbb.utils import cust_filter
 __MODULE__ = "Ping"
 __HELP__ = " - /ping - to check if I am Alive or Not"
 
-@app.on_message(cust_filter.command(commands = (["ping"])))
+
+@app.on_message(cust_filter.command(commands=(["ping"])))
 async def ping(client, message):
     start_time = int(round(time.time() * 1000))
     m = await message.reply_text("Starting Ping")
     end_time = int(round(time.time() * 1000))
-    await m.edit(f'{end_time - start_time} ms')
+    await m.edit(f"{end_time - start_time} ms")

+ 7 - 7
wbb/modules/stats.py

@@ -1,17 +1,17 @@
-from wbb import app, OWNER_ID
+from wbb import app, OWNER_ID, bot_start_time
+import time
 from pyrogram import filters
 import psutil
-from wbb.utils import cust_filter
+from wbb.utils import cust_filter, formater
 
 __MODULE__ = "Stats"
 __HELP__ = "For Bot Owner to Check system Status"
 
+
 @app.on_message(filters.user(OWNER_ID) & cust_filter.command(commands=(["stats"])))
 async def stats(client, message):
     cpu = psutil.cpu_percent(interval=0.5)
     mem = psutil.virtual_memory().percent
-    disk = psutil.disk_usage('/').percent
-    stats = f'<b>CPU:</b> {cpu}% ' \
-            f'<b>RAM:</b> {mem}% ' \
-            f'<b>Disk:</b> {disk}%'
-    await message.reply_text(stats)
+    disk = psutil.disk_usage("/").percent
+    stats = f"<b>Uptime:</b> {formater.get_readable_time((time.time() - bot_start_time))}" f"\n<b>CPU:</b> {cpu}% " f"\n<b>RAM:</b> {mem}% " f"\n<b>Disk:</b> {disk}%"
+    await message.reply_text(stats)

+ 1 - 1
wbb/utils/__init__.py

@@ -1,3 +1,3 @@
 from .read_lines import random_line
 from .botinfo import get_info
-from .misc import paginate_modules
+from .misc import paginate_modules

BIN
wbb/utils/__pycache__/__init__.cpython-37.pyc


BIN
wbb/utils/__pycache__/botinfo.cpython-37.pyc


BIN
wbb/utils/__pycache__/cust_filter.cpython-37.pyc


BIN
wbb/utils/__pycache__/misc.cpython-37.pyc


BIN
wbb/utils/__pycache__/read_lines.cpython-37.pyc


+ 177 - 0
wbb/utils/formater.py

@@ -0,0 +1,177 @@
+import time, math
+
+
+def time_formatter(seconds):
+    minutes, seconds = divmod(seconds, 60)
+    hours, minutes = divmod(minutes, 60)
+    days, hours = divmod(hours, 24)
+    tmp = (
+        ((str(days) + " day(s), ") if days else "")
+        + ((str(hours) + " hour(s), ") if hours else "")
+        + ((str(minutes) + " minute(s), ") if minutes else "")
+        + ((str(seconds) + " second(s), ") if seconds else "")
+    )
+    return tmp[:-2]
+
+
+def time_parser(start, end):
+    time_end = end - start
+    month = time_end // 2678400
+    days = time_end // 86400
+    hours = time_end // 3600 % 24
+    minutes = time_end // 60 % 60
+    seconds = time_end % 60
+    times = ""
+    if month:
+        times += "{} month, ".format(month)
+    if days:
+        times += "{} days, ".format(days)
+    if hours:
+        times += "{} hours, ".format(hours)
+    if minutes:
+        times += "{} minutes, ".format(minutes)
+    if seconds:
+        times += "{} seconds".format(seconds)
+    if times == "":
+        times = "{} miliseconds".format(time_end)
+    return times
+
+
+def time_parser_int(time_end):
+    month = time_end // 2678400
+    days = time_end // 86400
+    hours = time_end // 3600 % 24
+    minutes = time_end // 60 % 60
+    seconds = time_end % 60
+    times = ""
+    if month:
+        times += "{} month, ".format(month)
+    if days:
+        times += "{} days, ".format(days)
+    if hours:
+        times += "{} hours, ".format(hours)
+    if minutes:
+        times += "{} minutes, ".format(minutes)
+    if seconds:
+        times += "{} seconds".format(seconds)
+    if times == "":
+        times = "{} miliseconds".format(time_end)
+    return times[:-2] if times[-2:] == ", " else times
+
+
+def get_readable_time(seconds: int) -> str:
+    count = 0
+    ping_time = ""
+    time_list = []
+    time_suffix_list = ["s", "m", "h", "days"]
+    while count < 4:
+        count += 1
+        remainder, result = divmod(seconds, 60) if count < 3 else divmod(seconds, 24)
+        if seconds == 0 and remainder == 0:
+            break
+        time_list.append(int(result))
+        seconds = int(remainder)
+    for x in range(len(time_list)):
+        time_list[x] = str(time_list[x]) + time_suffix_list[x]
+    if len(time_list) == 4:
+        ping_time += time_list.pop() + ", "
+    time_list.reverse()
+    ping_time += ":".join(time_list)
+    return ping_time
+
+
+def convert_size(size_bytes):
+    if size_bytes == 0:
+        return "0B"
+    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
+    i = int(math.floor(math.log(size_bytes, 1024)))
+    p = math.pow(1024, i)
+    s = round(size_bytes / p, 2)
+    return "%s %s" % (s, size_name[i])
+
+
+def extract_time(time_val):
+    if not any(time_val.endswith(unit) for unit in ("m", "h", "d")):
+        return False
+    unit = time_val[-1]
+    time_num = time_val[:-1]  # type: str
+    if not time_num.isdigit():
+        return False
+
+    if unit == "d":
+        bantime = int(time.time() + int(time_num) * 24 * 60 * 60)
+    elif unit == "h":
+        bantime = int(time.time() + int(time_num) * 60 * 60)
+    elif unit == "m":
+        bantime = int(time.time() + int(time_num) * 60)
+    else:
+        return False
+    return bantime
+
+
+def make_time(time_val):
+    if int(time_val) == 0:
+        return "0"
+    if int(time_val) <= 3600:
+        bantime = str(int(time_val / 60)) + "m"
+    elif int(time_val) >= 3600 and time_val <= 86400:
+        bantime = str(int(time_val / 60 / 60)) + "h"
+    elif int(time_val) >= 86400:
+        bantime = str(int(time_val / 24 / 60 / 60)) + "d"
+    return bantime
+
+
+def extract_time_set(time_val):
+    if not any(time_val.endswith(unit) for unit in ("m", "h", "d")):
+        return False
+    unit = time_val[-1]
+    time_num = time_val[:-1]  # type: str
+    if not time_num.isdigit():
+        return False
+
+    if unit == "d":
+        bantime = int(int(time_num) * 24 * 60 * 60)
+    elif unit == "h":
+        bantime = int(int(time_num) * 60 * 60)
+    elif unit == "m":
+        bantime = int(int(time_num) * 60)
+    else:
+        return False
+    return bantime
+
+
+def escape_invalid_curly_brackets(text, valids):  # sourcery skip
+    new_text = ""
+    idx = 0
+    while idx < len(text):
+        if text[idx] == "{":
+            if idx + 1 < len(text) and text[idx + 1] == "{":
+                idx += 2
+                new_text += "{{{{"
+                continue
+            else:
+                success = False
+                for v in valids:
+                    if text[idx:].startswith("{" + v + "}"):
+                        success = True
+                        break
+                if success:
+                    new_text += text[idx : idx + len(v) + 2]
+                    idx += len(v) + 2
+                    continue
+                else:
+                    new_text += "{{"
+
+        elif text[idx] == "}":
+            if idx + 1 < len(text) and text[idx + 1] == "}":
+                idx += 2
+                new_text += "}}}}"
+                continue
+            else:
+                new_text += "}}"
+
+        else:
+            new_text += text[idx]
+        idx += 1
+
+    return new_text

+ 2 - 1
wbb/utils/read_lines.py

@@ -1,4 +1,5 @@
 import random
 
+
 async def random_line(fname):
-    return random.choice(open(fname).read().splitlines())
+    return random.choice(open(fname).read().splitlines())