Загрузка...

Тг бот для скупи токенов твич

Тема в разделе Python создана пользователем 0О0 14 май 2025. 108 просмотров

Загрузка...
  1. 0О0
    0О0 Автор темы 14 май 2025 lolz.live/threads/11111/ - Работайте с лучшими. 629 1 май 2022
    Данный бот предназначен для скупи токенов :twitch:
    Функции пользователя:

    • Регистрация через /start;
    • Указание профиля lolz (обязательно);
    • Загрузка .txt с Twitch-токенами;
    • Автоматическая проверка на уникальность токенов;
    • Получение уведомления о количестве уникальных и дубликатов;
    • Начисление выплат после ручной проверки админом;
    • Просмотр баланса и профиля;
    • Запрос на вывод средств с баланса.





    Функции администратора:

    • Получение .txt файла с уникальными токенами;
    • Кнопки “Начислить” и “Отклонить”;
    • Ввод суммы вручную;
    • Обработка заявок на вывод (выплата / отказ);
    • Просмотр статистики (токены, заявки, пользователи);
    • Выдача баланса по Telegram ID.


    Python
    import os
    import asyncio
    import logging
    from datetime import datetime
    from typing import Dict

    from aiogram import Bot, Dispatcher, F, types
    from aiogram.enums import ParseMode
    from aiogram.filters import Command, CommandStart
    from aiogram.types import Message, CallbackQuery, FSInputFile, ReplyKeyboardMarkup, KeyboardButton
    from aiogram.utils.keyboard import InlineKeyboardBuilder
    from aiogram.fsm.storage.memory import MemoryStorage

    from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, func, create_engine
    from sqlalchemy.orm import declarative_base, relationship, sessionmaker

    from dotenv import load_dotenv

    # Загрузка .env переменных
    load_dotenv()
    BOT_TOKEN = os.getenv("BOT_TOKEN")
    ADMIN_ID = int(os.getenv("ADMIN_ID", "0"))

    # Настройка *****
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)

    # --- База данных ---
    Base = declarative_base()
    engine = create_engine("sqlite:///db.sqlite3")
    SessionLocal = sessionmaker(bind=engine)

    class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    telegram_id = Column(Integer, unique=True)
    username = Column(String)
    balance = Column(Integer, default=0)
    lolz_profile = Column(String)
    uploaded_files = Column(Integer, default=0)

    class Token(Base):
    __tablename__ = "tokens"
    id = Column(Integer, primary_key=True)
    value = Column(String, unique=True)
    owner_id = Column(Integer, ForeignKey("users.id"))
    uploaded_at = Column(DateTime, default=func.now())
    review_id = Column(Integer, ForeignKey("token_reviews.id"))

    class TokenReviewRequest(Base):
    __tablename__ = "token_reviews"
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    file_name = Column(String)
    amount = Column(Integer, nullable=True)
    status = Column(String, default="pending")
    created_at = Column(DateTime, default=func.now())
    user = relationship("User", backref="token_reviews")
    tokens = relationship("Token", backref="review")

    class WithdrawalRequest(Base):
    __tablename__ = "withdrawals"
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    amount = Column(Integer)
    status = Column(String, default="pending")
    created_at = Column(DateTime, default=func.now())
    user = relationship("User", backref="withdrawals")

    Base.metadata.create_all(bind=engine)

    # --- Telegram бот ---
    bot = Bot(token=BOT_TOKEN, parse_mode=ParseMode.HTML)
    dp = Dispatcher(storage=MemoryStorage())

    pending_reviews: Dict[int, int] = {}
    pending_manual_balance: Dict[int, Dict[str, int]] = {}

    def format_number(num: int) -> str:
    return f"{num:,}".replace(",", ".")

    def main_menu_kb() -> ReplyKeyboardMarkup:
    return ReplyKeyboardMarkup(keyboard=[
    [KeyboardButton(text="Личный кабинет")],
    [KeyboardButton(text="Указать профиль lolz")],
    [KeyboardButton(text=" Вывести средства")]
    ], resize_keyboard=True)

    @dp.message(CommandStart())
    async def start(message: Message):
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=message.from_user.id).first()
    if not user:
    user = User(telegram_id=message.from_user.id, username=message.from_user.username)
    session.add(user)
    session.commit()
    await message.answer("Привет! Укажи профиль lolz и можешь отправить .txt с токенами.", reply_markup=main_menu_kb())
    session.close()

    @dp.message(F.text.lower() == "указать профиль lolz")
    async def ask_lolz(message: Message):
    await message.answer("Отправь ссылку на профиль lolz:")

    @dp.message(F.text.startswith("https://lolz.guru/"))
    async def save_lolz(message: Message):
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=message.from_user.id).first()
    user.lolz_profile = message.text.strip()
    session.commit()
    session.close()
    await message.answer(" Профиль сохранён.")

    @dp.message(F.text.lower() == "личный кабинет")
    async def profile(message: Message):
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=message.from_user.id).first()
    await message.answer(
    f" @{user.username}\nБаланс: {user.balance}₽\nLolz: {user.lolz_profile or 'не указан'}"
    )
    session.close()

    @dp.message(F.text == " Вывести средства")
    async def withdraw(message: Message):
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=message.from_user.id).first()
    if user.balance <= 0:
    await message.answer("Недостаточно средств.")
    session.close()
    return
    if session.query(WithdrawalRequest).filter_by(user_id=user.id, status="pending").first():
    await message.answer("У вас уже есть активный запрос.")
    session.close()
    return
    session.add(WithdrawalRequest(user_id=user.id, amount=user.balance))
    session.commit()
    await message.answer(" Запрос на вывод отправлен. Ожидайте.")
    await bot.send_message(ADMIN_ID, f" Запрос на вывод: @{user.username} | {user.balance}₽\nLolz: {user.lolz_profile}")
    session.close()

    @dp.message(F.document)
    async def handle_file(message: Message):
    if not message.document.file_name.endswith(".txt"):
    await message.answer("Принимаются только .txt файлы.")
    return
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=message.from_user.id).first()
    if not user.lolz_profile:
    await message.answer("Сначала укажи профиль lolz.")
    session.close()
    return

    file = await bot.get_file(message.document.file_id)
    fbytes = await bot.download_file(file.file_path)
    lines = set(line.strip() for line in fbytes.read().decode().splitlines() if line.strip())

    added = []
    for token_str in lines:
    if not session.query(Token).filter_by(value=token_str).first():
    token = Token(value=token_str, owner_id=user.id)
    session.add(token)
    added.append(token_str)
    session.commit()

    if not added:
    await message.answer(" Все токены уже были загружены ранее.")
    session.close()
    return

    review = TokenReviewRequest(user_id=user.id, file_name=message.document.file_name)
    session.add(review)
    session.commit()
    for token_str in added:
    token = session.query(Token).filter_by(value=token_str).first()
    token.review_id = review.id
    session.commit()

    os.makedirs("admin_tokens", exist_ok=True)
    filename = f"{user.username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
    filepath = f"admin_tokens/{filename}"
    with open(filepath, "w", encoding="utf-8") as f:
    f.write("\n".join(added))
    file_to_send = FSInputFile(filepath)
    caption = (
    f" Заявка на проверку\n@{user.username}\nLolz: {user.lolz_profile}\n"
    f"Файл: {message.document.file_name}\n Уникальных токенов: {len(added)}"
    )
    kb = InlineKeyboardBuilder()
    kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}")
    kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}")
    await bot.send_document(ADMIN_ID, document=file_to_send, caption=caption, reply_markup=kb.as_markup())

    total = len(lines)
    duplicates = total - len(added)
    await message.answer(
    f" Файл получен.\nВсего: {total}\nУникальных: {len(added)}\nДубликатов: {duplicates}"
    )
    session.close()

    @dp.callback_query(F.data.startswith("review_pay:"))
    async def review_pay(callback: CallbackQuery):
    rid = int(callback.data.split(":")[1])
    pending_reviews[callback.from_user.id] = rid
    await callback.message.answer("Введите сумму выплаты пользователю:")

    @dp.message(F.text.regexp(r"^\d+$"))
    async def assign_review_or_manual(message: Message):
    aid = message.from_user.id
    session = SessionLocal()

    if aid in pending_reviews:
    rid = pending_reviews.pop(aid)
    amount = int(message.text)
    review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first()
    if review:
    review.amount = amount
    review.status = "paid"
    review.user.balance += amount
    session.commit()
    await message.answer(f" Начислено {amount}₽ пользователю @{review.user.username}.")
    await bot.send_message(review.user.telegram_id, f" Вам начислено {amount}₽ за токены.")
    session.close()
    return

    if aid in pending_manual_balance and "user_id" in pending_manual_balance[aid]:
    uid = pending_manual_balance[aid]["user_id"]
    amount = int(message.text)
    user = session.query(User).filter_by(telegram_id=uid).first()
    if user:
    user.balance += amount
    session.commit()
    await message.answer(f" Пользователю @{user.username} выдано {amount}₽.")
    await bot.send_message(uid, f" Вам начислено {amount}₽ администратором.")
    session.close()
    pending_manual_balance.pop(aid, None)

    @dp.callback_query(F.data.startswith("review_reject:"))
    async def review_reject(callback: CallbackQuery):
    rid = int(callback.data.split(":")[1])
    session = SessionLocal()
    review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first()
    if review:
    review.status = "rejected"
    session.commit()
    await callback.message.answer(" Заявка отклонена.")
    await bot.send_message(review.user.telegram_id, " Заявка отклонена администратором.")
    session.close()

    @dp.message(Command("admin"))
    async def admin_panel(message: Message):
    if message.from_user.id != ADMIN_ID:
    return
    kb = InlineKeyboardBuilder()
    kb.button(text=" Активные заявки", callback_data="token_checks")
    kb.button(text=" Активные выводы", callback_data="active_withdrawals")
    kb.button(text=" Статистика", callback_data="admin_stats")
    kb.button(text=" Выдать баланс", callback_data="give_balance_manual")
    await message.answer("Панель администратора:", reply_markup=kb.as_markup())

    @dp.callback_query(F.data == "token_checks")
    async def token_checks(callback: CallbackQuery):
    session = SessionLocal()
    reviews = session.query(TokenReviewRequest).filter_by(status="pending").all()
    for review in reviews:
    text = (
    f" Заявка #{review.id}\n@{review.user.username}\n"
    f"Lolz: {review.user.lolz_profile}\nID: {review.user.telegram_id}\n"
    f" Уникальных токенов: {len(review.tokens)}"
    )
    kb = InlineKeyboardBuilder()
    kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}")
    kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}")
    await callback.message.answer(text, reply_markup=kb.as_markup())
    session.close()

    @dp.callback_query(F.data == "active_withdrawals")
    async def show_withdrawals(callback: CallbackQuery):
    session = SessionLocal()
    requests = session.query(WithdrawalRequest).filter_by(status="pending").all()
    for req in requests:
    text = (
    f"Запрос #{req.id}\n@{req.user.username} — {req.amount}₽\n"
    f"Lolz: {req.user.lolz_profile}\nID: {req.user.telegram_id}"
    )
    kb = InlineKeyboardBuilder()
    kb.button(text=" Выплачено", callback_data=f"mark_paid:{req.id}")
    kb.button(text=" Отклонить", callback_data=f"reject_withdrawal:{req.id}")
    await callback.message.answer(text, reply_markup=kb.as_markup())
    session.close()

    @dp.callback_query(F.data.startswith("mark_paid:"))
    async def mark_paid(callback: CallbackQuery):
    wid = int(callback.data.split(":")[1])
    session = SessionLocal()
    req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first()
    if req and req.user.balance >= req.amount:
    req.status = "paid"
    req.user.balance -= req.amount
    session.commit()
    await callback.message.answer(" Выплата завершена.")
    await bot.send_message(req.user.telegram_id, f" Выплата {req.amount}₽ выполнена.")
    session.close()

    @dp.callback_query(F.data.startswith("reject_withdrawal:"))
    async def reject_w(callback: CallbackQuery):
    wid = int(callback.data.split(":")[1])
    session = SessionLocal()
    req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first()
    if req:
    req.status = "rejected"
    session.commit()
    await callback.message.answer(" Заявка отклонена.")
    await bot.send_message(req.user.telegram_id, " Заявка на вывод отклонена.")
    session.close()

    @dp.callback_query(F.data == "admin_stats")
    async def show_stats(callback: CallbackQuery):
    session = SessionLocal()
    users = session.query(User).count()
    tokens = session.query(Token).count()
    reviews = session.query(TokenReviewRequest).count()
    session.close()
    await callback.message.answer(
    f" Статистика:\nПользователей: {format_number(users)}\n"
    f"Токенов: {format_number(tokens)}\n"
    f"Заявок: {format_number(reviews)}"
    )

    @dp.callback_query(F.data == "give_balance_manual")
    async def start_manual_give(callback: CallbackQuery):
    pending_manual_balance[callback.from_user.id] = {}
    await callback.message.answer("Введите Telegram ID пользователя:")

    @dp.message(F.text.regexp(r"^\d{6,}$"))
    async def save_manual_user_id(message: Message):
    admin_id = message.from_user.id
    if admin_id not in pending_manual_balance or "user_id" in pending_manual_balance[admin_id]:
    return
    user_id = int(message.text)
    session = SessionLocal()
    user = session.query(User).filter_by(telegram_id=user_id).first()
    session.close()
    if not user:
    await message.answer(" Пользователь не найден.")
    pending_manual_balance.pop(admin_id, None)
    return
    pending_manual_balance[admin_id]["user_id"] = user_id
    await message.answer(f"Пользователь @{user.username} найден. Введите сумму:")

    # --- Запуск ---
    async def main():
    await dp.start_polling(bot)

    if __name__ == "__main__":
    asyncio.run(main())
     
Top