astralix Userbot
МенюMenu
03 / DEVELOPERS

Создай то,
чего не хватает.
Build what's
missing.

Python, одна идея и твой первый модуль.Python, an idea, and your first module.

Первый модульYour first module

Модуль — Python-файл с классом, унаследованным от loader.Module. @loader.tds подключает строки перевода, а @loader.command() регистрирует команду. Сохрани пример как hello.py.A module is a Python file containing a class derived from loader.Module. @loader.tds enables translated strings, and @loader.command() registers a command. Save this example as hello.py.

python
# © Your name, 2026
from .. import loader, utils


@loader.tds
class HelloMod(loader.Module):
    """A small greeting module."""

    strings = {"name": "Hello", "hello": "Hello, {}!"}
    strings_ru = {"hello": "Привет, {}!"}

    @loader.command()
    async def hello(self, message):
        """[name] — Send a greeting."""
        name = utils.get_args_raw(message) or "world"
        await utils.answer(
            message,
            self.strings["hello"].format(utils.escape_html(name)),
        )

Загрузи файл в Telegram, ответь на него .loadmod и вызови .hello Astralix. Команды по умолчанию доступны владельцу.Upload the file to Telegram, reply with .loadmod, then run .hello Astralix. Commands are owner-only by default.

Аргументы и ответыArguments and replies

utils.get_args_raw(message) возвращает строку после команды, utils.get_args(message) — разобранные аргументы. Для ответов используй utils.answer: он учитывает контекст сообщения.utils.get_args_raw(message) returns the text after the command; utils.get_args(message) returns parsed arguments. Use utils.answer for responses: it handles the message context.

python
@loader.command()
async def echo(self, message):
    """[text] — Repeat text."""
    text = utils.get_args_raw(message)
    await utils.answer(message, utils.escape_html(text or "…"))

Экранируй пользовательские строки через utils.escape_html перед вставкой в HTML. Не выдавай недоверенный текст за разметку.Escape user-supplied strings with utils.escape_html before inserting them into HTML.

Настройки модуляModule configuration

Создай loader.ModuleConfig в __init__. Поля появятся в .config. Валидатор задаёт допустимые значения.Create a loader.ModuleConfig in __init__. Its fields appear in .config. A validator controls the allowed values.

python
def __init__(self):
    self.config = loader.ModuleConfig(
        loader.ConfigValue(
            "greeting",
            "Hello",
            "Greeting text",
            validator=loader.validators.String(),
        ),
    )

@loader.command()
async def greet(self, message):
    """Send the configured greeting."""
    await utils.answer(
        message, utils.escape_html(self.config["greeting"])
    )

Клиент и хранениеClient and storage

client_ready вызывается после подготовки клиента и конфигурации. Храни небольшие JSON-совместимые значения через self.get и self.set. Не складывай секреты в исходники или логи.client_ready runs after the client and configuration are ready. Store small JSON-compatible values using self.get and self.set. Keep secrets out of source code and logs.

python
async def client_ready(self, client, db):
    self.client = client

@loader.command()
async def counter(self, message):
    """Increment a persistent counter."""
    count = self.get("count", 0) + 1
    self.set("count", count)
    await utils.answer(message, str(count))

Обработчики событийEvent handlers

Для наблюдения за сообщениями используй @loader.watcher(). Ограничивай обработчик нужными событиями и не отвечай на каждое сообщение: это может создать цикл.Use @loader.watcher() to observe messages. Restrict it to relevant events and avoid replying to every message, which can create a loop.

python
@loader.watcher()
async def watcher(self, message):
    if not getattr(message, "out", False):
        return
    if getattr(message, "raw_text", "") == "astralix:count":
        self.set("matches", self.get("matches", 0) + 1)

Rich-сообщения и медиаRich messages and media

Передай HTML в rich_message. Для обычного сообщения используй текст и URL в file. Не путай публичную ссылку с локальным путём.Pass HTML using rich_message. For a regular message, use text and a URL in file. A public URL and a local path are different media sources.

python
await utils.answer(
    message,
    rich_message="<h1>Hello</h1><p>Built with astralix.</p>",
)

await utils.answer(
    message,
    "Hello",
    file="https://raw.githubusercontent.com/lowsense-dev/"
         "astralix/refs/heads/main/assets/astralix-banner.png",
)

astralix-tl и асинхронностьastralix-tl and async code

Импортируй Telegram API из astralixtl. Сетевые операции клиента нужно ожидать через await. Не блокируй цикл событий через time.sleep или синхронные HTTP-запросы.Import the Telegram API from astralixtl. Await client network operations. Do not block the event loop with time.sleep or synchronous HTTP requests.

python
from astralixtl.tl.types import Message
import asyncio

# Inside an async handler:
await asyncio.sleep(1)

Смотри рабочие примеры в модулях ядра и реализацию декораторов в loader.py.See working examples in the core modules and decorator implementations in loader.py.