mirror of https://github.com/coddrago/Heroku
Merge branch 'dev-test' of https://github.com/coddrago/Heroku into dev-test
commit
733708e2ca
|
@ -379,6 +379,7 @@ updater:
|
||||||
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Updates werden installiert...</b>"
|
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Updates werden installiert...</b>"
|
||||||
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Neustart erfolgreich! {}</b>\n<i>Die Module werden jedoch noch geladen...</i>\n<i>Der Neustart dauerte {} Sekunden</i>"
|
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Neustart erfolgreich! {}</b>\n<i>Die Module werden jedoch noch geladen...</i>\n<i>Der Neustart dauerte {} Sekunden</i>"
|
||||||
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Der Userbot ist vollständig geladen! {}</b>\n<i>Der vollständige Neustart dauerte {} Sekunden.</i>"
|
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Der Userbot ist vollständig geladen! {}</b>\n<i>Der vollständige Neustart dauerte {} Sekunden.</i>"
|
||||||
|
ub_stop: "Dein {} wurde gestoppt!"
|
||||||
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Sicherer Start abgeschlossen! {}</b>\n<i>Der Neustart dauerte {} Sekunden</i>"
|
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Sicherer Start abgeschlossen! {}</b>\n<i>Der Neustart dauerte {} Sekunden</i>"
|
||||||
origin_cfg_doc: "Die URL, von der die Updates heruntergeladen werden"
|
origin_cfg_doc: "Die URL, von der die Updates heruntergeladen werden"
|
||||||
btn_restart: "🔄 Neu starten"
|
btn_restart: "🔄 Neu starten"
|
||||||
|
|
|
@ -419,6 +419,7 @@ updater:
|
||||||
cancel: "🚫 Cancel"
|
cancel: "🚫 Cancel"
|
||||||
lavhost_update: "<emoji document_id=5469986291380657759>✌️</emoji> <b>Your {} is updating...</b>"
|
lavhost_update: "<emoji document_id=5469986291380657759>✌️</emoji> <b>Your {} is updating...</b>"
|
||||||
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Userbot is fully loaded! {}</b>\n<i>Full restart took {}s</i>"
|
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Userbot is fully loaded! {}</b>\n<i>Full restart took {}s</i>"
|
||||||
|
ub_stop: "Your {emoji} has been stopped"
|
||||||
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Secure boot completed! {}</b>\n<i>Restart took {}s</i>"
|
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Secure boot completed! {}</b>\n<i>Restart took {}s</i>"
|
||||||
invalid_args: "<emoji document_id=5210952531676504517>🚫</emoji> <b>You must provide number of commits to rollback!</b>"
|
invalid_args: "<emoji document_id=5210952531676504517>🚫</emoji> <b>You must provide number of commits to rollback!</b>"
|
||||||
rollback_too_far: "<emoji document_id=5210952531676504517>🚫</emoji> <b>You're rolling back too far!</b>"
|
rollback_too_far: "<emoji document_id=5210952531676504517>🚫</emoji> <b>You're rolling back too far!</b>"
|
||||||
|
|
|
@ -379,6 +379,7 @@ updater:
|
||||||
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Установка обновлений...</b>"
|
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Установка обновлений...</b>"
|
||||||
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Перезагрузка успешна! {}</b>\n<i>Но модули еще загружаются...</i>\n<i>Перезагрузка заняла {} сек</i>"
|
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Перезагрузка успешна! {}</b>\n<i>Но модули еще загружаются...</i>\n<i>Перезагрузка заняла {} сек</i>"
|
||||||
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Юзербот полностью загружен! {}</b>\n<i>Полная перезагрузка заняла {} сек.</i>"
|
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Юзербот полностью загружен! {}</b>\n<i>Полная перезагрузка заняла {} сек.</i>"
|
||||||
|
ub_stop: "Твоя {emoji} остановлена!"
|
||||||
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Безопасная загрузка завершена! {}</b>\n<i>Перезагрузка заняла {} сек</i>"
|
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Безопасная загрузка завершена! {}</b>\n<i>Перезагрузка заняла {} сек</i>"
|
||||||
origin_cfg_doc: "Ссылка, из которой будут загружаться обновления"
|
origin_cfg_doc: "Ссылка, из которой будут загружаться обновления"
|
||||||
btn_restart: "🔄 Перезагрузиться"
|
btn_restart: "🔄 Перезагрузиться"
|
||||||
|
|
|
@ -379,6 +379,7 @@ updater:
|
||||||
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Встановлення оновлень...</b>"
|
installing: "<emoji document_id=5208622108191506906>🕗</emoji> <b>Встановлення оновлень...</b>"
|
||||||
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Перезавантаження успішне! {}</b>\n<i>Але модулі ще завантажуються...</i>\n<i>Перезавантаження зайняло {} сек</i>"
|
success: "<emoji document_id=5208661316947955396>⏱</emoji> <b>Перезавантаження успішне! {}</b>\n<i>Але модулі ще завантажуються...</i>\n<i>Перезавантаження зайняло {} сек</i>"
|
||||||
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Юзербот повністю завантажений! {}</b>\n<i>Повне перезавантаження зайняло {} сек</i>"
|
full_success: "<emoji document_id=6028215594707324419>👍</emoji> <b>Юзербот повністю завантажений! {}</b>\n<i>Повне перезавантаження зайняло {} сек</i>"
|
||||||
|
ub_stop: "Твоя {} остановлена!"
|
||||||
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Безпечне завантаження завершено! {}</b>\n<i>Перезавантаження зайняло {} сек</i>"
|
secure_boot_complete: "<emoji document_id=5472308992514464048>🔐</emoji> <b>Безпечне завантаження завершено! {}</b>\n<i>Перезавантаження зайняло {} сек</i>"
|
||||||
origin_cfg_doc: "Посилання, з якого будуть завантажуватися оновлення"
|
origin_cfg_doc: "Посилання, з якого будуть завантажуватися оновлення"
|
||||||
btn_restart: "🔄 Перезавнтаження"
|
btn_restart: "🔄 Перезавнтаження"
|
||||||
|
|
|
@ -27,10 +27,14 @@ from logging.handlers import RotatingFileHandler
|
||||||
import herokutl
|
import herokutl
|
||||||
from aiogram.exceptions import TelegramNetworkError
|
from aiogram.exceptions import TelegramNetworkError
|
||||||
from herokutl.errors import PersistentTimestampOutdatedError
|
from herokutl.errors import PersistentTimestampOutdatedError
|
||||||
|
from herokutl.errors.rpcbaseerrors import (
|
||||||
|
ServerError,
|
||||||
|
RPCError
|
||||||
|
)
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .tl_cache import CustomTelegramClient
|
from .tl_cache import CustomTelegramClient
|
||||||
from .types import BotInlineCall, Module
|
from .types import BotInlineCall, Module, CoreOverwriteError
|
||||||
from .web.debugger import WebDebugger
|
from .web.debugger import WebDebugger
|
||||||
|
|
||||||
# Monkeypatch linecache to make interactive line debugger available
|
# Monkeypatch linecache to make interactive line debugger available
|
||||||
|
@ -72,11 +76,25 @@ linecache.getlines = getlines
|
||||||
|
|
||||||
def override_text(exception: Exception) -> typing.Optional[str]:
|
def override_text(exception: Exception) -> typing.Optional[str]:
|
||||||
"""Returns error-specific description if available, else `None`"""
|
"""Returns error-specific description if available, else `None`"""
|
||||||
|
|
||||||
if isinstance(exception, (TelegramNetworkError, asyncio.exceptions.TimeoutError)):
|
if isinstance(exception, (TelegramNetworkError, asyncio.exceptions.TimeoutError)):
|
||||||
return "✈️ <b>You have problems with internet connection on your server.</b>"
|
return "✈️ <b>You have problems with internet connection on your server.</b>"
|
||||||
elif isinstance(exception, PersistentTimestampOutdatedError):
|
|
||||||
|
if isinstance(exception, PersistentTimestampOutdatedError):
|
||||||
return "✈️ <b>Telegram has problems with their datacenters.</b>"
|
return "✈️ <b>Telegram has problems with their datacenters.</b>"
|
||||||
|
|
||||||
|
if isinstance(exception, CoreOverwriteError):
|
||||||
|
return f"⚠️ {str(exception)}"
|
||||||
|
|
||||||
|
if isinstance(exception, ServerError):
|
||||||
|
return "📡 <b>Telegram servers are currently experiencing issues. Please try again later.</b>"
|
||||||
|
|
||||||
|
if isinstance(exception, RPCError) and "TRANSLATION_TIMEOUT" in str(exception):
|
||||||
|
return ("🕓 <b>Telegram translation service timed out. Please try again later.</b>")
|
||||||
|
|
||||||
|
if isinstance(exception, ModuleNotFoundError):
|
||||||
|
return f"📦 {traceback.format_exception_only(type(exception), exception)[0].split(':')[1].strip()}"
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -205,12 +205,6 @@ def generate_random_system_version():
|
||||||
return version
|
return version
|
||||||
|
|
||||||
|
|
||||||
if not IS_WINDOWS:
|
|
||||||
import uvloop
|
|
||||||
|
|
||||||
uvloop.install()
|
|
||||||
|
|
||||||
|
|
||||||
def run_config():
|
def run_config():
|
||||||
"""Load configurator.py"""
|
"""Load configurator.py"""
|
||||||
from . import configurator
|
from . import configurator
|
||||||
|
|
|
@ -137,71 +137,76 @@ class HerokuWebMod(loader.Module):
|
||||||
|
|
||||||
@loader.command()
|
@loader.command()
|
||||||
async def addacc(self, message: Message):
|
async def addacc(self, message: Message):
|
||||||
id = utils.get_args(message)
|
|
||||||
if not id:
|
if "JAMHOST" in os.environ or "HIKKAHOST" in os.environ or "LAVHOST" in os.environ or "SHARKHOST" in os.environ:
|
||||||
reply = await message.get_reply_message()
|
await utils.answer(message, self.strings["host_denied"])
|
||||||
id = reply.sender_id if reply else None
|
|
||||||
else:
|
else:
|
||||||
id = id[0]
|
|
||||||
|
|
||||||
user = None
|
|
||||||
if id:
|
|
||||||
try:
|
|
||||||
id = int(id)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
id = utils.get_args(message)
|
||||||
user = await self._client.get_entity(id)
|
if not id:
|
||||||
except Exception as e:
|
reply = await message.get_reply_message()
|
||||||
logger.error(f"Error while fetching user: {e}")
|
id = reply.sender_id if reply else None
|
||||||
|
else:
|
||||||
|
id = id[0]
|
||||||
|
|
||||||
|
user = None
|
||||||
|
if id:
|
||||||
|
try:
|
||||||
|
id = int(id)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
if not user or not isinstance(user, User) or user.bot:
|
try:
|
||||||
await utils.answer(
|
user = await self._client.get_entity(id)
|
||||||
message,
|
except Exception as e:
|
||||||
self.strings("invalid_target")
|
logger.error(f"Error while fetching user: {e}")
|
||||||
)
|
|
||||||
return
|
if not user or not isinstance(user, User) or user.bot:
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings("invalid_target")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if user.id == self._client.tg_id:
|
if user.id == self._client.tg_id:
|
||||||
await utils.answer(
|
await utils.answer(
|
||||||
message,
|
message,
|
||||||
self.strings("cant_add_self")
|
self.strings("cant_add_self")
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if "force_insecure" in message.text.lower():
|
if "force_insecure" in message.text.lower():
|
||||||
await self._inline_login(message, user)
|
await self._inline_login(message, user)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not await self.inline.form(
|
if not await self.inline.form(
|
||||||
self.strings("add_user_confirm").format(
|
self.strings("add_user_confirm").format(
|
||||||
|
utils.escape_html(user.first_name),
|
||||||
|
user.id,
|
||||||
|
),
|
||||||
|
message=message,
|
||||||
|
reply_markup=[
|
||||||
|
{
|
||||||
|
"text": self.strings("btn_yes"),
|
||||||
|
"callback": self._inline_login,
|
||||||
|
"args": (user,),
|
||||||
|
},
|
||||||
|
{"text": self.strings("btn_no"), "action": "close"},
|
||||||
|
],
|
||||||
|
photo="",
|
||||||
|
):
|
||||||
|
raise Exception
|
||||||
|
except Exception:
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings("add_user_insecure").format(
|
||||||
utils.escape_html(user.first_name),
|
utils.escape_html(user.first_name),
|
||||||
user.id,
|
user.id,
|
||||||
),
|
utils.escape_html(self.get_prefix()),
|
||||||
message=message,
|
user.id,
|
||||||
reply_markup=[
|
)
|
||||||
{
|
|
||||||
"text": self.strings("btn_yes"),
|
|
||||||
"callback": self._inline_login,
|
|
||||||
"args": (user,),
|
|
||||||
},
|
|
||||||
{"text": self.strings("btn_no"), "action": "close"},
|
|
||||||
],
|
|
||||||
photo="",
|
|
||||||
):
|
|
||||||
raise Exception
|
|
||||||
except Exception:
|
|
||||||
await utils.answer(
|
|
||||||
message,
|
|
||||||
self.strings("add_user_insecure").format(
|
|
||||||
utils.escape_html(user.first_name),
|
|
||||||
user.id,
|
|
||||||
utils.escape_html(self.get_prefix()),
|
|
||||||
user.id,
|
|
||||||
)
|
)
|
||||||
)
|
return
|
||||||
return
|
|
||||||
|
|
||||||
async def _inline_login(self, call: typing.Union[Message, InlineCall], user: User, after_fail: bool = False):
|
async def _inline_login(self, call: typing.Union[Message, InlineCall], user: User, after_fail: bool = False):
|
||||||
reply_markup = [
|
reply_markup = [
|
||||||
|
|
|
@ -34,6 +34,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import typing
|
import typing
|
||||||
|
import signal
|
||||||
|
|
||||||
import herokutl
|
import herokutl
|
||||||
|
|
||||||
|
@ -131,9 +132,9 @@ class MessageEditor:
|
||||||
|
|
||||||
class SudoMessageEditor(MessageEditor):
|
class SudoMessageEditor(MessageEditor):
|
||||||
# Let's just hope these are safe to parse
|
# Let's just hope these are safe to parse
|
||||||
PASS_REQ = "[sudo] password for"
|
PASS_REQ = ["[sudo] password for", "[sudo] пароль для"]
|
||||||
WRONG_PASS = r"\[sudo\] password for (.*): Sorry, try again\."
|
WRONG_PASS = [r"\[sudo\] password for (.*): Sorry, try again\.", r"\[sudo\] пароль для (.*): Попробуйте еще раз.\."]
|
||||||
TOO_MANY_TRIES = (r"\[sudo\] password for (.*): sudo: [0-9]+ incorrect password attempts") # fmt: skip
|
TOO_MANY_TRIES = [r"\[sudo\] password for (.*): sudo: [0-9]+ incorrect password attempts", r"\[sudo\] пароль для (.*): sudo: [0-9]+ неверные попытки ввода пароля"] # fmt: skip
|
||||||
|
|
||||||
def __init__(self, message, command, config, strings, request_message):
|
def __init__(self, message, command, config, strings, request_message):
|
||||||
super().__init__(message, command, config, strings, request_message)
|
super().__init__(message, command, config, strings, request_message)
|
||||||
|
@ -155,20 +156,21 @@ class SudoMessageEditor(MessageEditor):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
len(lines) > 1
|
len(lines) > 1
|
||||||
and re.fullmatch(self.WRONG_PASS, lines[-2])
|
and any(re.fullmatch(i, lines[-2]) for i in self.WRONG_PASS)
|
||||||
and lastlines[0] == self.PASS_REQ
|
and any(lastlines[0] == i for i in self.PASS_REQ)
|
||||||
and self.state == 1
|
and self.state == 1
|
||||||
):
|
):
|
||||||
logger.debug("switching state to 0")
|
logger.debug("switching state to 0")
|
||||||
await self.authmsg.edit(self.strings("auth_failed"))
|
await utils.answer(message, self.strings("auth_fail"))
|
||||||
self.state = 0
|
self.state = 0
|
||||||
handled = True
|
handled = True
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
await self.authmsg.delete()
|
if self.authmsg:
|
||||||
|
await self.authmsg.delete()
|
||||||
|
|
||||||
if lastlines[0] == self.PASS_REQ and self.state == 0:
|
if any(lastlines[0] == i for i in self.PASS_REQ) and self.state == 0:
|
||||||
logger.debug("Success to find sudo log!")
|
logger.debug("Success to find sudo log!")
|
||||||
text = self.strings("auth_needed").format(self._tg_id)
|
text = self.strings("auth_needed").format(self.message.client.heroku_me.id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await utils.answer(self.message, text)
|
await utils.answer(self.message, text)
|
||||||
|
@ -179,14 +181,14 @@ class SudoMessageEditor(MessageEditor):
|
||||||
command = "<code>" + utils.escape_html(self.command) + "</code>"
|
command = "<code>" + utils.escape_html(self.command) + "</code>"
|
||||||
user = utils.escape_html(lastlines[1][:-1])
|
user = utils.escape_html(lastlines[1][:-1])
|
||||||
|
|
||||||
self.authmsg = await self.message[0].client.send_message(
|
self.authmsg = await self.message.client.send_message(
|
||||||
"me",
|
"me",
|
||||||
self.strings("auth_msg").format(command, user),
|
self.strings("auth_msg").format(command, user),
|
||||||
)
|
)
|
||||||
logger.debug("sent message to self")
|
logger.debug("sent message to self")
|
||||||
|
|
||||||
self.message[0].client.remove_event_handler(self.on_message_edited)
|
self.message.client.remove_event_handler(self.on_message_edited)
|
||||||
self.message[0].client.add_event_handler(
|
self.message.client.add_event_handler(
|
||||||
self.on_message_edited,
|
self.on_message_edited,
|
||||||
herokutl.events.messageedited.MessageEdited(chats=["me"]),
|
herokutl.events.messageedited.MessageEdited(chats=["me"]),
|
||||||
)
|
)
|
||||||
|
@ -195,7 +197,7 @@ class SudoMessageEditor(MessageEditor):
|
||||||
handled = True
|
handled = True
|
||||||
|
|
||||||
if len(lines) > 1 and (
|
if len(lines) > 1 and (
|
||||||
re.fullmatch(self.TOO_MANY_TRIES, lastline) and self.state in {1, 3, 4}
|
any(re.fullmatch(i, lastline) for i in self.TOO_MANY_TRIES) and self.state in {1, 3, 4}
|
||||||
):
|
):
|
||||||
logger.debug("password wrong lots of times")
|
logger.debug("password wrong lots of times")
|
||||||
await utils.answer(self.message, self.strings("auth_locked"))
|
await utils.answer(self.message, self.strings("auth_locked"))
|
||||||
|
@ -206,7 +208,7 @@ class SudoMessageEditor(MessageEditor):
|
||||||
if not handled:
|
if not handled:
|
||||||
logger.debug("Didn't find sudo log.")
|
logger.debug("Didn't find sudo log.")
|
||||||
if self.authmsg is not None:
|
if self.authmsg is not None:
|
||||||
await self.authmsg[0].delete()
|
await self.authmsg.delete()
|
||||||
self.authmsg = None
|
self.authmsg = None
|
||||||
self.state = 2
|
self.state = 2
|
||||||
await self.redraw()
|
await self.redraw()
|
||||||
|
@ -363,8 +365,8 @@ class TerminalMod(loader.Module):
|
||||||
if needsswitch:
|
if needsswitch:
|
||||||
cmd = " ".join([cmd.split(" ", 1)[0], "-S", cmd.split(" ", 1)[1]])
|
cmd = " ".join([cmd.split(" ", 1)[0], "-S", cmd.split(" ", 1)[1]])
|
||||||
|
|
||||||
sproc = await asyncio.create_subprocess_shell(
|
sproc = await asyncio.create_subprocess_exec(
|
||||||
cmd,
|
"/bin/bash", "-c", cmd,
|
||||||
stdin=asyncio.subprocess.PIPE,
|
stdin=asyncio.subprocess.PIPE,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.PIPE,
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
@ -404,12 +406,11 @@ class TerminalMod(loader.Module):
|
||||||
|
|
||||||
if hash_msg(await message.get_reply_message()) in self.activecmds:
|
if hash_msg(await message.get_reply_message()) in self.activecmds:
|
||||||
try:
|
try:
|
||||||
|
kill_pids = self.activecmds[hash_msg(await message.get_reply_message())]
|
||||||
if "-f" not in utils.get_args_raw(message):
|
if "-f" not in utils.get_args_raw(message):
|
||||||
self.activecmds[
|
os.killpg(kill_pids.pid, signal.SIGTERM)
|
||||||
hash_msg(await message.get_reply_message())
|
|
||||||
].terminate()
|
|
||||||
else:
|
else:
|
||||||
self.activecmds[hash_msg(await message.get_reply_message())].kill()
|
os.killpg(kill_pids.pid, signal.SIGKILL)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Killing process failed")
|
logger.exception("Killing process failed")
|
||||||
await utils.answer(message, self.strings("kill_fail"))
|
await utils.answer(message, self.strings("kill_fail"))
|
||||||
|
|
|
@ -697,10 +697,8 @@ class UpdaterMod(loader.Module):
|
||||||
"""| stops your userbot"""
|
"""| stops your userbot"""
|
||||||
|
|
||||||
if "LAVHOST" in os.environ:
|
if "LAVHOST" in os.environ:
|
||||||
await utils.answer(message, self.strings[" lavhost_stop"])
|
await utils.answer(message, self.strings["ub_stop"].format(emoji=utils.get_platform_emoji()))
|
||||||
await self.client.send_message("lavhostbot", "⏹ Stop")
|
await self.client.send_message("lavhostbot", "⏹ Stop")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await utils.answer(message, self.strings[" ub_stop"])
|
await utils.answer(message, self.strings["ub_stop"].format(emoji=utils.get_platform_emoji()))
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
heroku-tl-new==1.1.3
|
heroku-tl-new==1.1.3
|
||||||
Pillow
|
Pillow
|
||||||
uvloop; sys_platform != 'win32'
|
|
||||||
|
|
||||||
# Python 3.9+
|
# Python 3.9+
|
Loading…
Reference in New Issue