mirror of https://github.com/coddrago/Heroku
1.1.8: Add `on_dlmod` hook, fix translations, fix okteto pinger and some minor stuff
More info in t.me/hikka_ubpull/1/head
parent
185457140d
commit
f56a380fc6
|
@ -154,4 +154,8 @@ config.json
|
|||
*.jpg
|
||||
*.jpeg
|
||||
*.webp
|
||||
*.webm
|
||||
*.webm
|
||||
*.tgs
|
||||
*.mp4
|
||||
*.mp3
|
||||
*.ogg
|
|
@ -8,20 +8,35 @@ class Module:
|
|||
"""There is no help for this module"""
|
||||
|
||||
def config_complete(self):
|
||||
"""Will be called when module.config is populated"""
|
||||
"""Called when module.config is populated"""
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
"""Will be called after client is ready (after config_loaded)"""
|
||||
"""Called after client is ready (after config_loaded)"""
|
||||
|
||||
async def on_unload(self):
|
||||
"""Will be called after unloading / reloading module"""
|
||||
"""Called after unloading / reloading module"""
|
||||
|
||||
# Called after client_ready, for internal use only. Must not be used by non-core modules
|
||||
async def _client_ready2(self, client, db):
|
||||
pass
|
||||
"""Called after client_ready, for internal use only. Must not be used by non-core modules"""
|
||||
|
||||
async def on_dlmod(self, client, db):
|
||||
"""
|
||||
Called after the module is first time loaded with .dlmod or .loadmod
|
||||
|
||||
Possible use-cases:
|
||||
- Send reaction to author's channel message
|
||||
- Join author's channel
|
||||
- Create asset folder
|
||||
- ...
|
||||
|
||||
⚠️ Note, that any error there will not interrupt module load, and will just
|
||||
send a message to logs with verbosity INFO and exception traceback
|
||||
"""
|
||||
|
||||
|
||||
class LoadError(Exception):
|
||||
"""Tells user, why your module can't be loaded, if rased in `client_ready`"""
|
||||
|
||||
def __init__(self, error_message: str): # skipcq: PYL-W0231
|
||||
self._error = error_message
|
||||
|
||||
|
@ -29,6 +44,16 @@ class LoadError(Exception):
|
|||
return self._error
|
||||
|
||||
|
||||
class SelfUnload(Exception):
|
||||
"""Silently unloads module, if raised in `client_ready`"""
|
||||
|
||||
def __init__(self, error_message: str = ""): # skipcq: PYL-W0231
|
||||
self._error = error_message
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self._error
|
||||
|
||||
|
||||
class StopLoop(Exception):
|
||||
"""Stops the loop, in which is raised"""
|
||||
|
||||
|
|
|
@ -379,15 +379,15 @@
|
|||
"hikka.modules.animefy._cmd_doc_animefy": "<reply> - Нарисовать фото",
|
||||
"hikka.modules.animefy._cls_doc": "Делает из реальных людей мультяшек",
|
||||
"hikka.modules.temp_chat.chat_is_being_removed": "<b>🚫 Чат удаляется...</b>",
|
||||
"hikka.modules.temp_chat.args": "<b>Капец с аргументами: </b><code>.help TempChat</code>",
|
||||
"hikka.modules.temp_chat.chat_not_found": "<b>Чат не найден</b>",
|
||||
"hikka.modules.temp_chat.tmp_cancelled": "<b>Чат </b><code>{}</code><b> будет жить вечно!</b>",
|
||||
"hikka.modules.temp_chat.delete_error": "<b>Произошла ошибка удаления чата. Сделай это вручную.</b>",
|
||||
"hikka.modules.temp_chat.args": "🚫 <b>Капец с аргументами: </b><code>.help TempChat</code>",
|
||||
"hikka.modules.temp_chat.chat_not_found": "🚫 <b>Чат не найден</b>",
|
||||
"hikka.modules.temp_chat.tmp_cancelled": "🚫 <b>Чат </b><code>{}</code><b> будет жить вечно!</b>",
|
||||
"hikka.modules.temp_chat.delete_error": "🚫 <b>Произошла ошибка удаления чата. Сделай это вручную.</b>",
|
||||
"hikka.modules.temp_chat.temp_chat_header": "<b>⚠️ Этот чат</b> (<code>{}</code>)<b> является временным и будет удален {}.</b>",
|
||||
"hikka.modules.temp_chat.chat_created": "<b>Чат создан</b>",
|
||||
"hikka.modules.temp_chat.delete_error_me": "<b>Ошибка удаления чата {}</b>",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpchat": "<время> <название> - Создать новый временный чат\nВремя можно указать в таком формате: 30s, 30min, 1h, 1d, 1w, 1m",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpcurrent": "<время> - Создать новый временный чат\nВремя можно указать в таком формате: 30s, 30min, 1h, 1d, 1w, 1m",
|
||||
"hikka.modules.temp_chat.chat_created": "✅ <b><a href=\"{}\">Чат</a> создан</b>",
|
||||
"hikka.modules.temp_chat.delete_error_me": "🚫 <b>Ошибка удаления чата {}</b>",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpchat": "<время> <название> - Создать новый временный чат",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpcurrent": "<время> - Создать новый временный чат",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpchats": "Показать временные чаты",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpcancel": "[chat-id] - Отменить удаление чата.",
|
||||
"hikka.modules.temp_chat._cmd_doc_tmpctime": "<chat_id> <новое время> - Изменить время жизни чата",
|
||||
|
@ -809,5 +809,12 @@
|
|||
"hikka.modules.hikka_backup.period": "⌚️ <b>Приветики! Я Асуна</b> - твой менеджер резервного копирования. Пожалуйста, выбери периодичность резервных копий базы данных Hikka",
|
||||
"hikka.modules.hikka_backup.saved": "✅ Периодичность сохранена! Ее можно изменить с помощью .set_backup_period",
|
||||
"hikka.modules.hikka_backup.never": "✅ Я не буду делать автоматические резервные копии. Можно отменить используя .set_backup_period",
|
||||
"hikka.modules.hikka_backup.invalid_args": "🚫 <b>Укажи правильную периодичность в часах, или `0` для отключения</b>"
|
||||
"hikka.modules.hikka_backup.invalid_args": "🚫 <b>Укажи правильную периодичность в часах, или `0` для отключения</b>",
|
||||
"hikka.modules.hikka_info.owner": "Владелец",
|
||||
"hikka.modules.hikka_info.version": "Версия",
|
||||
"hikka.modules.hikka_info.build": "Сборка",
|
||||
"hikka.modules.hikka_info.prefix": "Префикс команд",
|
||||
"hikka.modules.hikka_info.send_info": "Отправить информацию о юзерботе",
|
||||
"hikka.modules.hikka_info.description": "ℹ Это не раскроет никакой личной информации",
|
||||
"hikka.modules.hikka_info._ihandle_doc_info": "Отправить информацию о юзерботе"
|
||||
}
|
|
@ -39,7 +39,7 @@ from importlib.abc import SourceLoader
|
|||
from . import utils, security
|
||||
from .translations import Strings
|
||||
from .inline.core import InlineManager
|
||||
from ._types import Module, LoadError, ModuleConfig, StopLoop # noqa: F401
|
||||
from ._types import Module, LoadError, ModuleConfig, StopLoop, SelfUnload # noqa: F401
|
||||
|
||||
from importlib.machinery import ModuleSpec
|
||||
from types import FunctionType
|
||||
|
@ -303,7 +303,6 @@ class Modules:
|
|||
len(x) > 3
|
||||
and x[-3:] == ".py"
|
||||
and x[0] != "_"
|
||||
and ("OKTETO" in os.environ or x != "okteto.py")
|
||||
and (
|
||||
not db.get("hikka", "disable_quickstart", False)
|
||||
or x != "quickstart.py"
|
||||
|
@ -489,6 +488,10 @@ class Modules:
|
|||
mod=instance.strings["name"],
|
||||
)
|
||||
|
||||
instance.get_prefix = lambda: (
|
||||
self._db.get("hikka.main", "command_prefix", False) or "."
|
||||
)
|
||||
|
||||
for module in self.modules:
|
||||
if module.__class__.__name__ == instance.__class__.__name__:
|
||||
if getattr(module, "__origin__", "") == "<core>":
|
||||
|
@ -612,12 +615,32 @@ class Modules:
|
|||
if self.added_modules:
|
||||
await self.added_modules(self)
|
||||
|
||||
async def send_ready_one(self, mod, client, db, allclients):
|
||||
async def send_ready_one(
|
||||
self,
|
||||
mod: Module,
|
||||
client: "TelegramClient", # noqa: F821
|
||||
db: "Database", # noqa: F821
|
||||
allclients: list,
|
||||
no_self_unload: bool = False,
|
||||
from_dlmod: bool = False,
|
||||
):
|
||||
mod.allclients = allclients
|
||||
mod.inline = self.inline
|
||||
|
||||
if from_dlmod:
|
||||
try:
|
||||
await mod.on_dlmod(client, db)
|
||||
except Exception:
|
||||
logging.info("Can't process `on_dlmod` hook", exc_info=True)
|
||||
|
||||
try:
|
||||
await mod.client_ready(client, db)
|
||||
except SelfUnload as e:
|
||||
if no_self_unload:
|
||||
raise e
|
||||
|
||||
logging.debug(f"Unloading {mod}, because it raised SelfUnload")
|
||||
self.modules.remove(mod)
|
||||
except Exception as e:
|
||||
logging.exception(f"Failed to send mod init complete signal for {mod} due to {e}, attempting unload") # fmt: skip
|
||||
self.modules.remove(mod)
|
||||
|
|
|
@ -25,7 +25,15 @@ logger = logging.getLogger(__name__)
|
|||
class HikkaInfoMod(loader.Module):
|
||||
"""Show userbot info"""
|
||||
|
||||
strings = {"name": "HikkaInfo"}
|
||||
strings = {
|
||||
"name": "HikkaInfo",
|
||||
"owner": "Owner",
|
||||
"version": "Version",
|
||||
"build": "Build",
|
||||
"prefix": "Command prefix",
|
||||
"send_info": "Send userbot info",
|
||||
"description": "ℹ This will not compromise any sensitive info",
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
|
@ -34,13 +42,10 @@ class HikkaInfoMod(loader.Module):
|
|||
self.markup = {"text": "🌘 Support chat", "url": "https://t.me/hikka_talks"}
|
||||
|
||||
def _render_info(self) -> str:
|
||||
try:
|
||||
repo = git.Repo()
|
||||
ver = repo.heads[0].commit.hexsha
|
||||
except Exception:
|
||||
ver = "unknown"
|
||||
ver = utils.get_git_hash() or "Unknown"
|
||||
|
||||
try:
|
||||
repo = git.Repo()
|
||||
diff = repo.git.log(["HEAD..origin/master", "--oneline"])
|
||||
upd = (
|
||||
"⚠️ Update required </b><code>.update</code><b>"
|
||||
|
@ -52,10 +57,10 @@ class HikkaInfoMod(loader.Module):
|
|||
|
||||
return (
|
||||
"<b>🌘 Hikka Userbot</b>\n"
|
||||
f'<b>🤴 Owner: <a href="tg://user?id={self._me.id}">{utils.escape_html(get_display_name(self._me))}</a></b>\n\n'
|
||||
f"<b>🔮 Version: </b><i>{'.'.join(list(map(str, list(main.__version__))))}</i>\n"
|
||||
f"<b>🧱 Build: </b><a href=\"https://github.com/hikariatama/Hikka/commit/{ver}\">{ver[:8] or 'Unknown'}</a>\n"
|
||||
f"<b>📼 Command prefix: </b>«<code>{utils.escape_html((self._db.get(main.__name__, 'command_prefix', False) or '.')[0])}</code>»\n"
|
||||
f'<b>🤴 {self.strings("owner")}: <a href="tg://user?id={self._me.id}">{utils.escape_html(get_display_name(self._me))}</a></b>\n\n'
|
||||
f"<b>🔮 {self.strings('version')}: </b><i>{'.'.join(list(map(str, list(main.__version__))))}</i>\n"
|
||||
f"<b>🧱 {self.strings('build')}: </b><a href=\"https://github.com/hikariatama/Hikka/commit/{ver}\">{ver[:8]}</a>\n\n"
|
||||
f"<b>📼 {self.strings('prefix')}: </b>«<code>{utils.escape_html(self.get_prefix())}</code>»\n"
|
||||
f"<b>{upd}</b>\n"
|
||||
f"<b>{utils.get_named_platform()}</b>\n"
|
||||
)
|
||||
|
@ -65,8 +70,8 @@ class HikkaInfoMod(loader.Module):
|
|||
"""Send userbot info"""
|
||||
|
||||
return {
|
||||
"title": "Send userbot info",
|
||||
"description": "ℹ This will not compromise any sensitive data",
|
||||
"title": self.strings("send_info"),
|
||||
"description": self.strings("description"),
|
||||
"message": self._render_info(),
|
||||
"thumb": "https://github.com/hikariatama/Hikka/raw/master/assets/hikka_pfp.png",
|
||||
"reply_markup": self.markup,
|
||||
|
|
|
@ -523,6 +523,7 @@ class LoaderMod(loader.Module):
|
|||
save_fs,
|
||||
) # Try again
|
||||
except loader.LoadError as e:
|
||||
self.allmodules.modules.remove(instance)
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
return
|
||||
|
@ -535,15 +536,6 @@ class LoaderMod(loader.Module):
|
|||
return
|
||||
|
||||
instance.inline = self.inline
|
||||
instance.get = functools.partial(
|
||||
self._mod_get,
|
||||
mod=instance.strings["name"],
|
||||
)
|
||||
instance.set = functools.partial(
|
||||
self._mod_set,
|
||||
mod=instance.strings["name"],
|
||||
)
|
||||
|
||||
instance.animate = self._animate
|
||||
|
||||
for method in dir(instance):
|
||||
|
@ -564,8 +556,17 @@ class LoaderMod(loader.Module):
|
|||
self._client,
|
||||
self._db,
|
||||
self.allclients,
|
||||
no_self_unload=True,
|
||||
from_dlmod=bool(message),
|
||||
)
|
||||
except loader.LoadError as e:
|
||||
self.allmodules.modules.remove(instance)
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
return
|
||||
except loader.SelfUnload as e:
|
||||
logging.debug(f"Unloading {instance}, because it raised `SelfUnload`")
|
||||
self.allmodules.modules.remove(instance)
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
return
|
||||
|
@ -584,9 +585,6 @@ class LoaderMod(loader.Module):
|
|||
modname = getattr(instance, "name", "ERROR")
|
||||
|
||||
modhelp = ""
|
||||
prefix = utils.escape_html(
|
||||
(self._db.get(main.__name__, "command_prefix", False) or ".")
|
||||
)
|
||||
|
||||
if instance.__doc__:
|
||||
modhelp += (
|
||||
|
@ -612,7 +610,7 @@ class LoaderMod(loader.Module):
|
|||
instance.commands.items(),
|
||||
key=lambda x: x[0],
|
||||
):
|
||||
modhelp += self.strings("single_cmd").format(prefix, _name)
|
||||
modhelp += self.strings("single_cmd").format(self.get_prefix(), _name)
|
||||
|
||||
if fun.__doc__:
|
||||
modhelp += utils.escape_html(inspect.getdoc(fun))
|
||||
|
@ -690,12 +688,6 @@ class LoaderMod(loader.Module):
|
|||
self.strings("unloaded" if worked else "not_unloaded"),
|
||||
)
|
||||
|
||||
def _mod_get(self, *args, mod: str = None) -> Any:
|
||||
return self._db.get(mod, *args)
|
||||
|
||||
def _mod_set(self, *args, mod: str = None) -> bool:
|
||||
return self._db.set(mod, *args)
|
||||
|
||||
async def _animate(
|
||||
self,
|
||||
message: Union[Message, InlineMessage],
|
||||
|
@ -726,7 +718,7 @@ class LoaderMod(loader.Module):
|
|||
message = await self.inline.form(
|
||||
message=message,
|
||||
text=frame,
|
||||
reply_markup={"text": ".", "data": "empty"},
|
||||
reply_markup={"text": "\u0020\u2800", "data": "empty"},
|
||||
)
|
||||
else:
|
||||
message = await utils.answer(message, frame)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# 🔒 Licensed under the GNU GPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from .. import loader, utils
|
||||
from .. import loader, utils, main
|
||||
import logging
|
||||
import asyncio
|
||||
import os
|
||||
|
@ -16,6 +16,8 @@ import time
|
|||
from telethon.tl.functions.messages import GetScheduledHistoryRequest
|
||||
from telethon.tl.types import Message
|
||||
|
||||
from .._types import SelfUnload
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -26,8 +28,6 @@ class OktetoMod(loader.Module):
|
|||
strings = {"name": "Okteto"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
if "OKTETO" not in os.environ:
|
||||
raise loader.LoadError("This module can be loaded only if userbot is installed to ☁️ Okteto") # fmt: skip
|
||||
|
||||
self._db = db
|
||||
self._client = client
|
||||
|
@ -38,21 +38,40 @@ class OktetoMod(loader.Module):
|
|||
self._exception_timeout = 10
|
||||
self._send_interval = 5
|
||||
self._bot = "@WebpageBot"
|
||||
|
||||
if "OKTETO" not in os.environ:
|
||||
messages = (
|
||||
await client(
|
||||
GetScheduledHistoryRequest(
|
||||
peer=self._bot,
|
||||
hash=0,
|
||||
),
|
||||
)
|
||||
).messages
|
||||
|
||||
if messages:
|
||||
logger.info("Deleting previously scheduled Okteto pinger messages")
|
||||
|
||||
for message in messages:
|
||||
await message.delete()
|
||||
|
||||
raise SelfUnload
|
||||
|
||||
await utils.dnd(client, await client.get_entity(self._bot), True)
|
||||
self._task = asyncio.ensure_future(self._okteto_poller())
|
||||
self._task = asyncio.ensure_future(self._okteto_pinger())
|
||||
|
||||
async def on_unload(self):
|
||||
self._task.cancel()
|
||||
|
||||
async def _okteto_poller(self):
|
||||
async def _okteto_pinger(self):
|
||||
"""Creates queue to Webpage bot to reset Okteto polling after app goes to sleep"""
|
||||
while True:
|
||||
try:
|
||||
if not self._db.get("hikka", "okteto_uri", False):
|
||||
if not main.get_config_key("okteto_uri"):
|
||||
await asyncio.sleep(self._env_wait_interval)
|
||||
continue
|
||||
|
||||
uri = self._db.get("hikka", "okteto_uri")
|
||||
uri = main.get_config_key("okteto_uri")
|
||||
current_queue = (
|
||||
await self._client(
|
||||
GetScheduledHistoryRequest(
|
||||
|
@ -87,8 +106,8 @@ class OktetoMod(loader.Module):
|
|||
async def watcher(self, message: Message):
|
||||
if (
|
||||
not getattr(message, "raw_text", False)
|
||||
or not self._db.get("hikka", "okteto_uri", False)
|
||||
or self._db.get("hikka", "okteto_uri") not in message.raw_text
|
||||
or not main.get_config_key("okteto_uri")
|
||||
or main.get_config_key("okteto_uri") not in message.raw_text
|
||||
and "Link previews was updated successfully" not in message.raw_text
|
||||
or utils.get_chat_id(message) != 169642392
|
||||
):
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# 🔒 Licensed under the GNU GPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from .. import loader
|
||||
from .. import loader, translations
|
||||
import logging
|
||||
from aiogram.types import CallbackQuery
|
||||
from random import choice
|
||||
|
@ -29,11 +29,15 @@ TEXT = """🌘🇬🇧 <b>Hello.</b> You've just installed <b>Hikka</b> userbot.
|
|||
|
||||
❓ <b>Need help?</b> Feel free to join our support chat. We help <b>everyone</b>.
|
||||
|
||||
📼 <b>Official modules sources: </b>
|
||||
📼 <b>Official modules sources:</b>
|
||||
▫️ @hikarimods
|
||||
▫️ @hikarimods_database
|
||||
▫️ <code>.dlmod</code>
|
||||
|
||||
✅ <b>Trusted modules' developers:</b>
|
||||
▫️ @morisummermods
|
||||
▫️ @cakestwix_mods
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
@ -41,11 +45,14 @@ TEXT_RU = """🌘🇷🇺 <b>Привет.</b> Твой юзербот <b>Hikka<
|
|||
|
||||
❓ <b>Нужна помощь?</b> Вступай в наш чат поддержки. Мы помогаем <b>всем</b>.
|
||||
|
||||
📼 <b>Официальные источники модулей: </b>
|
||||
📼 <b>Официальные источники модулей:</b>
|
||||
▫️ @hikarimods
|
||||
▫️ @hikarimods_database
|
||||
▫️ <code>.dlmod</code>
|
||||
|
||||
✅ <b>Доверенные разработчики модулей:</b>
|
||||
▫️ @morisummermods
|
||||
▫️ @cakestwix_mods
|
||||
"""
|
||||
|
||||
if "OKTETO" in os.environ:
|
||||
|
@ -61,6 +68,7 @@ class QuickstartMod(loader.Module):
|
|||
|
||||
async def client_ready(self, client, db):
|
||||
self._me = (await client.get_me()).id
|
||||
self._db = db
|
||||
|
||||
mark = self.inline._generate_markup(
|
||||
[
|
||||
|
@ -92,6 +100,11 @@ class QuickstartMod(loader.Module):
|
|||
]
|
||||
)
|
||||
|
||||
self._db.set(translations.__name__, "lang", "ru")
|
||||
self._db.set(translations.__name__, "pack", "ru")
|
||||
await self.translator.init()
|
||||
await call.answer("🇷🇺 Язык сохранен!")
|
||||
|
||||
await self.inline.bot.edit_message_caption(
|
||||
chat_id=call.message.chat.id,
|
||||
message_id=call.message.message_id,
|
||||
|
@ -107,6 +120,11 @@ class QuickstartMod(loader.Module):
|
|||
]
|
||||
)
|
||||
|
||||
self._db.set(translations.__name__, "lang", "en")
|
||||
self._db.set(translations.__name__, "pack", None)
|
||||
await self.translator.init()
|
||||
await call.answer("🇬🇧 Language saved!")
|
||||
|
||||
await self.inline.bot.edit_message_caption(
|
||||
chat_id=call.message.chat.id,
|
||||
message_id=call.message.message_id,
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = (1, 1, 7)
|
||||
__version__ = (1, 1, 8)
|
||||
|
|
Loading…
Reference in New Issue