$ sudo teach IT
Модуль 8 · Интеграции с Telegram-ботами

Урок 8.6 — Интеграция с python-telegram-bot (PTB)

Учимся интегрировать aiosend с python-telegram-bot (PTB) — асинхронной библиотекой с Application Builder и современным API.

python-telegram-bot (PTB) v20+ — это полностью асинхронная библиотека, использующая Application и ApplicationBuilder. Интеграция с aiosend естественна: обе библиотеки асинхронные. Запускаем app.run_polling() и cp.start_polling() параллельно.

🏗️

ApplicationBuilder — современный подход PTB

PTB v20+ использует паттерн Builder для создания приложения. ApplicationBuilder позволяет сконфигурировать бота, добавить обработчики и запустить polling.

Python · Параллельный запуск PTB + aiosend
import asyncio
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, CallbackQueryHandler
from aiosend import CryptoPay

BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"

cp = CryptoPay(token=CP_TOKEN)

# PTB handler — Command
async def start(update: Update, context):
    await update.message.reply_text(
        "Привет! Я бот на PTB + aiosend!\n"
        "Используй /pay 10 USDT для оплаты."
    )

async def pay(update: Update, context):
    args = context.args
    if len(args) < 2:
        await update.message.reply_text("Пример: /pay 10 USDT")
        return

    amount, asset = float(args[0]), args[1].upper()
    invoice = await cp.create_invoice(
        amount=amount,
        asset=asset,
        payload=str(update.effective_user.id),
    )

    await update.message.reply_text(
        f"🧾 Счёт на {amount} {asset}:\n"
        f"{invoice.bot_invoice_url}"
    )

@cp.invoice_paid()
async def on_paid(invoice):
    from telegram import Bot
    bot = Bot(token=BOT_TOKEN)
    user_id = int(invoice.payload)
    await bot.send_message(
        user_id,
        f"✅ Оплата {invoice.amount} {invoice.asset} получена!",
    )

async def main():
    # Создаём PTB Application
    app = (
        Application.builder()
        .token(BOT_TOKEN)
        .build()
    )

    # Регистрируем хендлеры
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("pay", pay))

    # Запускаем параллельно
    await asyncio.gather(
        app.run_polling(),   # PTB
        cp.start_polling(),  # aiosend
    )

asyncio.run(main())

💡 Особенность PTB

app.run_polling() — это синхронная обёртка, которая создаёт event loop и запускает бота. Чтобы запустить aiosend параллельно, мы используем asyncio.gather() с app.run_polling(), который в PTB v20+ можно вызвать как корутину.

🎣

Различные обработчики PTB

PTB предоставляет множество готовых классов-обработчиков: CommandHandler, MessageHandler, CallbackQueryHandler и другие.

Python · Различные обработчики PTB
from telegram.ext import (
    CommandHandler,
    MessageHandler,
    CallbackQueryHandler,
    filters,
)

# CommandHandler — для команд
app.add_handler(CommandHandler("buy", buy_handler))

# MessageHandler — для текстовых сообщений
app.add_handler(
    MessageHandler(filters.TEXT & ~filters.COMMAND, text_handler)
)

# CallbackQueryHandler — для inline-кнопок
app.add_handler(CallbackQueryHandler(callback_handler, pattern="^buy_"))

# Несколько команд в одном обработчике
app.add_handler(CommandHandler(["help", "info"], help_handler))

🔍 Параметры PTB-хендлеров

  • update — объект Update с данными от Telegram
  • context — объект ContextTypes с дополнительной информацией
  • context.args — аргументы команды (для CommandHandler)
  • context.user_data — данные пользователя (словарь)
  • update.effective_user.id — ID пользователя
🚀

Полный пример: магазин на PTB

Python · Полный бот на PTB
import asyncio
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
    Application,
    CommandHandler,
    CallbackQueryHandler,
    ContextTypes,
)
from aiosend import CryptoPay

BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"

cp = CryptoPay(token=CP_TOKEN)

PRODUCTS = {
    "premium": {"name": "Премиум", "price": 15, "asset": "USDT"},
    "vip": {"name": "VIP-доступ", "price": 50, "asset": "USDT"},
}

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    kb = InlineKeyboardMarkup([
        [InlineKeyboardButton("💎 Премиум", callback_data="buy_premium")],
        [InlineKeyboardButton("⭐ VIP", callback_data="buy_vip")],
    ])
    await update.message.reply_text("🛒 Добро пожаловать!", reply_markup=kb)

async def buy_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()

    product_key = query.data.replace("buy_", "")
    product = PRODUCTS.get(product_key)
    if not product:
        await query.message.reply_text("Товар не найден")
        return

    invoice = await cp.create_invoice(
        amount=product["price"],
        asset=product["asset"],
        description=product["name"],
        payload=f"{query.from_user.id}:{product_key}",
    )

    msg = await query.message.reply_text(
        f"💳 {product['name']}\n"
        f"Сумма: {product['price']} {product['asset']}\n\n"
        f"🔗 {invoice.bot_invoice_url}\n\n"
        f"⏳ Ожидаем оплату...",
        parse_mode="HTML",
    )

    try:
        paid = await invoice.poll(message=msg)
        await msg.edit_text(
            f"✅ Оплачено!\n"
            f"{paid.paid_amount} {paid.paid_asset}\n"
            f"Товар: {product['name']}",
            parse_mode="HTML",
        )
    except Exception as e:
        await msg.edit_text(f"❌ Ошибка: {e}")

@cp.invoice_paid()
async def on_paid(invoice):
    from telegram import Bot
    bot = Bot(token=BOT_TOKEN)
    user_id, product_key = invoice.payload.split(":")
    product = PRODUCTS.get(product_key, {"name": "товар"})
    print(f"Платёж: user={user_id} product={product['name']}")
    await bot.send_message(
        int(user_id),
        f"✅ {product['name']} активирован! Спасибо!",
    )

async def main():
    app = (
        Application.builder()
        .token(BOT_TOKEN)
        .build()
    )
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CallbackQueryHandler(buy_callback, pattern="^buy_"))

    await asyncio.gather(
        app.run_polling(),
        cp.start_polling(),
    )

asyncio.run(main())

🔍 Ключевые особенности PTB

  • Application.builder().token(TOKEN).build() — создание приложения
  • app.add_handler(CommandHandler("cmd", func)) — регистрация команд
  • app.add_handler(CallbackQueryHandler(func, pattern)) — callback-кнопки
  • update.callback_query — для работы с callback
  • context.args — аргументы команды (после /cmd)
  • await query.answer() — ответ на callback
⏳

Ожидание оплаты с PTB

invoice.poll(message=msg) работает и с PTB. Объект Message из PTB v20+ поддерживается aiosend.

Python · Invoice.poll с PTB
async def buy(update: Update, context: ContextTypes.DEFAULT_TYPE):
    invoice = await cp.create_invoice(
        amount=10, asset="USDT",
        payload=str(update.effective_user.id),
    )

    msg = await update.message.reply_text(
        f"💳 Счёт на 10 USDT\n{invoice.bot_invoice_url}\n\n⏳ Ожидаем..."
    )

    try:
        paid = await invoice.poll(message=msg)
        await msg.edit_text(
            f"✅ Оплачено: {paid.paid_amount} {paid.paid_asset}"
        )
    except Exception as e:
        await msg.edit_text(f"❌ Ошибка: {e}")
📌

Что важно запомнить

1️⃣
ApplicationBuilder — создание и конфигурация бота.
2️⃣
CommandHandler, CallbackQueryHandler — регистрация обработчиков.
3️⃣
asyncio.gather() — параллельный запуск PTB и aiosend.
4️⃣
context.args — аргументы команды, update.effective_user.id — ID пользователя.
🎯

Практическое задание

Задание: Donate-бот на PTB

Создай бота на PTB + aiosend:

  • По команде /donate [сумма] [валюта] создаёт инвойс
  • Отправляет ссылку на оплату
  • Ожидает оплату через invoice.poll(message=msg)
  • Благодарит пользователя после оплаты
  • Запускает через asyncio.gather()

Подсказка:

Python · Шаблон решения
import asyncio
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
from aiosend import CryptoPay

cp = CryptoPay(token="CP_TOKEN")

async def donate(update: Update, context: ContextTypes.DEFAULT_TYPE):
    args = context.args
    amount, asset = float(args[0]), args[1].upper()
    invoice = await cp.create_invoice(
        amount=amount, asset=asset,
        payload=str(update.effective_user.id),
    )
    msg = await update.message.reply_text(f"💛 {invoice.bot_invoice_url}")
    paid = await invoice.poll(message=msg)
    await msg.edit_text(f"✅ Спасибо за {paid.paid_amount} {paid.paid_asset}!")

async def main():
    app = Application.builder().token("BOT_TOKEN").build()
    app.add_handler(CommandHandler("donate", donate))
    await asyncio.gather(app.run_polling(), cp.start_polling())

asyncio.run(main())

Урок 8.6: Интеграция с python-telegram-bot

5 вопросов