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

Урок 8.4 — Интеграция с Pyrogram

Учимся интегрировать aiosend с Pyrogram — асинхронной библиотекой для работы с MTProto API Telegram.

Pyrogram — это асинхронная библиотека, использующая MTProto протокол Telegram. Интеграция с aiosend естественна: обе библиотеки асинхронные. Запускаем Pyrogram через app.run(), а aiosend polling — в параллельной корутине.

⚡

Параллельный запуск Pyrogram + aiosend

Pyrogram использует app.run() для запуска, aiosend — cp.start_polling(). Обе корутины можно запустить через asyncio.gather() или используя app.run() с asyncio.ensure_future() внутри.

Python · Параллельный запуск
import asyncio
from pyrogram import Client, filters
from aiosend import CryptoPay

BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"
API_ID = 12345
API_HASH = "0123456789abcdef0123456789abcdef"

app = Client("my_bot", bot_token=BOT_TOKEN, api_id=API_ID, api_hash=API_HASH)
cp = CryptoPay(token=CP_TOKEN)

@app.on_message(filters.command("start"))
async def start(client, message):
    await message.reply(
        "Привет! Я бот на Pyrogram + aiosend!\n"
        "Используй /pay 10 USDT для оплаты."
    )

@app.on_message(filters.command("pay"))
async def pay(client, message):
    args = message.text.split()[1:]
    if len(args) < 2:
        await message.reply("Пример: /pay 10 USDT")
        return

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

    await message.reply(
        f"🧾 Счёт на {amount} {asset}:\n"
        f"{invoice.bot_invoice_url}\n"
        f"Mini App: {invoice.mini_app_invoice_url}"
    )

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

async def main():
    await asyncio.gather(
        app.start(),           # Pyrogram
        cp.start_polling(),    # aiosend
    )

asyncio.run(main())

💡 Вариант с app.run()

Вместо asyncio.gather() можно использовать app.run(), который запускает внутренний event loop. В этом случае aiosend нужно запустить через asyncio.ensure_future() внутри самого бота, например, в обработчике @app.on_startup().

⏳

Ожидание оплаты с invoice.poll()

В Pyrogram invoice.poll(message=message) также работает. Объект Message в Pyrogram поддерживается aiosend.

Python · Invoice.poll с Pyrogram
@app.on_message(filters.command("buy"))
async def buy(client, message):
    invoice = await cp.create_invoice(
        amount=15,
        asset="USDT",
        description="Премиум",
        payload=str(message.from_user.id),
    )

    msg = await message.reply(
        f"💳 Премиум\n"
        f"Сумма: 15 USDT\n\n"
        f"🔗 {invoice.bot_invoice_url}\n\n"
        f"⏳ Ожидаем оплату...",
    )

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

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

Python · Полный бот на Pyrogram
import asyncio
from pyrogram import Client, filters
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiosend import CryptoPay

BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"
API_ID = 12345
API_HASH = "0123456789abcdef0123456789abcdef"

app = Client("shop_bot", bot_token=BOT_TOKEN, api_id=API_ID, api_hash=API_HASH)
cp = CryptoPay(token=CP_TOKEN)

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

@app.on_message(filters.command("start"))
async def start(client, message):
    kb = InlineKeyboardMarkup([
        [InlineKeyboardButton("💎 Премиум", callback_data="buy_premium")],
        [InlineKeyboardButton("⭐ VIP", callback_data="buy_vip")],
    ])
    await message.reply("🛒 Добро пожаловать!", reply_markup=kb)

@app.on_callback_query(filters.regex(r"^buy_"))
async def handle_buy(client, callback):
    product_key = callback.data.replace("buy_", "")
    product = PRODUCTS.get(product_key)
    if not product:
        await callback.answer("Товар не найден")
        return

    await callback.answer("Создаём счёт...")

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

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

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

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

async def main():
    await asyncio.gather(
        app.start(),
        cp.start_polling(),
    )

asyncio.run(main())

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

  • Pyrogram требует api_id и api_hash (получить на my.telegram.org)
  • Декораторы: @app.on_message(filters.command("x")) и @app.on_callback_query()
  • app.start() — корутина, её нужно await
  • Pyrogram использует MTProto вместо Bot API
  • await message.reply() — отправка ответа
📌

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

1️⃣
asyncio.gather(app.start(), cp.start_polling()) — запуск.
2️⃣
Pyrogram — асинхронный, как и aiosend. Не требуется threading.
3️⃣
invoice.poll(message=msg) — работает, msg редактируется при оплате.
4️⃣
@cp.invoice_paid() — глобальный хендлер для уведомлений.
🎯

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

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

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

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

Подсказка:

Python · Шаблон решения
import asyncio
from pyrogram import Client, filters
from aiosend import CryptoPay

app = Client("bot", bot_token="TOKEN", api_id=1, api_hash="hash")
cp = CryptoPay(token="CP_TOKEN")

@app.on_message(filters.command("donate"))
async def donate(client, message):
    args = message.text.split()
    amount, asset = float(args[1]), args[2].upper()
    invoice = await cp.create_invoice(
        amount=amount, asset=asset,
        payload=str(message.from_user.id),
    )
    msg = await message.reply(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():
    await asyncio.gather(app.start(), cp.start_polling())

asyncio.run(main())

Урок 8.4: Интеграция с Pyrogram

5 вопросов