Предыстория: два мессенджера, две кодовые базы
Max запустили как полноценную альтернативу Telegram для российского рынка, с открытым Bot API. Разработчики оказались перед классической дилеммой: поддерживать двойную кодовую базу или выбрать одну платформу, теряя аудиторию второй.
Типичная ситуация выглядит так: есть готовый Telegram-бот на aiogram, и нужно запустить его ещё в Max. Варианты неприятные: либо дублировать код, либо писать тонну адаптеров вручную, либо мириться с расхождением фич между платформами.
Библиотека obabot предлагает другой путь: один код — два мессенджера, чтобы править всеми.
Что такое obabot?
obabot — это асинхронная Python-библиотека с API, совместимым с aiogram 3.x, которая позволяет запускать одного бота сразу на Telegram и Max. Под капотом: для Telegram используется нативный aiogram без какой-либо дополнительной обёртки, а для Max — адаптерный слой, который транслирует события Max-платформы в aiogram-совместимые объекты.
Устанавливается одной командой:
pip install obabot aiogram>=3.0.0 umaxbot>=0.1.7
Быстрый старт
Центральная точка входа — функция create_bot(). Она принимает токены нужных платформ и возвращает готовый кортеж (bot, dispatcher, router).
Только Telegram
from obabot import create_bot from obabot.filters import Command bot, dp, router = create_bot(tg_token="ВАШ_TG_ТОКЕН") @router.message(Command("start")) async def start(message): await message.answer(f"Привет с {message.platform}!") await dp.start_polling(bot)
Только Max
from obabot import create_bot from obabot.filters import Command bot, dp, router = create_bot(max_token="ВАШ_MAX_ТОКЕН") @router.message(Command("start")) async def start(message): await message.answer(f"Привет с {message.platform}!") await dp.start_polling(bot)
Обратите внимание: код обработчика абсолютно идентичен. Разница только в аргументе токена. В каждый объект добавляется атрибут platform для написания платформ-специфичного кода
Обе платформы одновременно
from obabot import create_bot from obabot.filters import Command bot, dp, router = create_bot( tg_token="ВАШ_TG_ТОКЕН", max_token="ВАШ_MAX_ТОКЕН" ) @router.message(Command("start")) async def start(message): # Атрибут platform показывает, откуда пришло сообщение await message.answer(f"Привет с {message.platform}!") # Polling запускается на обеих платформах параллельно await dp.start_polling(bot)
Миграция с aiogram за 5 минут
Если у вас уже есть бот на aiogram 3.x, миграция сводится к замене импортов и инициализации.
До:
from aiogram import Bot, Dispatcher, Router from aiogram.filters import Command from aiogram.fsm.state import State, StatesGroup from aiogram.fsm.context import FSMContext bot = Bot(token="TOKEN") dp = Dispatcher() router = Router() dp.include_router(router) @router.message(Command("start")) async def start(message): await message.answer("Привет!") await dp.start_polling(bot)
После:
from obabot import create_bot from obabot.filters import Command from obabot.fsm import State, StatesGroup, FSMContext bot, dp, router = create_bot(tg_token="TOKEN") @router.message(Command("start")) async def start(message): await message.answer("Привет!") await dp.start_polling(bot)
Изменилось ровно 2 вещи:
импорты:
aiogram→obabotинициализация:
Bot/Dispatcher/Router→create_bot()
всё остальное осталось 100% идентичным
Поддерживаемые возможности
Объект Message
Все сообщения — и из Telegram, и из Max — реализуют единый интерфейс:
message.text # Текст сообщения message.from_user # Пользователь message.chat # Чат message.message_id # ID сообщения message.platform # "telegram" или "max" await message.answer("Ответ") await message.reply("Ответить на сообщение") await message.delete() await message.edit_text("Новый текст")
FSM (Finite State Machine, машина состояний, конечный автомат)
FSM работает так же, как в aiogram:
from obabot.fsm import State, StatesGroup, FSMContext class Form(StatesGroup): name = State() age = State() @router.message(Command("start")) async def start(message, state: FSMContext): await state.set_state(Form.name) await message.answer("Как тебя зовут?") @router.message(Form.name) async def process_name(message, state: FSMContext): await state.update_data(name=message.text) await state.set_state(Form.age) await message.answer("Сколько тебе лет?")
Инлайн-клавиатуры
from obabot.types import InlineKeyboardMarkup, InlineKeyboardButton keyboard = InlineKeyboardMarkup(inline_keyboard=[ [ InlineKeyboardButton(text="Кнопка 1", callback_data="btn1"), InlineKeyboardButton(text="Кнопка 2", callback_data="btn2"), ] ]) await message.answer("Выберите:", reply_markup=keyboard)
Фильтры
from obabot.filters import Command, F @router.message(Command("start", "help")) # Несколько команд @router.message(F.text.startswith("!")) # Магический фильтр @router.message(F.photo) # Только фото @router.callback_query(F.data == "click") # Callback
Тестовый режим
Для unit-тестов предусмотрен специальный режим — токены не нужны, сетевых вызовов нет:
bot, dp, router = create_bot(test_mode=True)
Тесты покрывают Python 3.10, 3.13, 3.14 и aiogram 3.0.0, 3.24.
Репозиторий: github.com/Korean-DOG/obabot
Итог
obabot закрывает конкретную практическую боль: запускать Telegram-бота ещё и в Max без переписывания кода.
