Files
quixotic/backend/bot.py
Andrey Kondratev d4debf9b63 python
2025-09-09 15:39:28 +05:00

163 lines
5.9 KiB
Python

import os
from typing import Optional
from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, WebAppInfo
from telegram.ext import Application, CommandHandler, MessageHandler, filters
import httpx
from .database import Database, User
class QuixoticBot:
def __init__(self, token: str, web_app_url: str, database: Database):
self.token = token
self.web_app_url = web_app_url
self.db = database
self.bot = Bot(token=token)
self.application = Application.builder().token(token).build()
self.setup_handlers()
def setup_handlers(self):
"""Setup bot command and message handlers"""
# Command handlers
self.application.add_handler(CommandHandler("start", self.start_command))
self.application.add_handler(CommandHandler("help", self.help_command))
# Message handlers
self.application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_message))
async def start_command(self, update, context):
"""Handle /start command"""
user = update.effective_user
chat_id = update.effective_chat.id
# Save or update user in database
try:
db_user = await self.db.get_user_by_telegram_id(str(user.id))
if not db_user:
await self.db.add_user(
telegram_id=str(user.id),
username=user.username,
first_name=user.first_name,
last_name=user.last_name,
language_code=user.language_code
)
except Exception as e:
print(f"Database error in start command: {e}")
# Create inline keyboard with web app button
keyboard = [
[InlineKeyboardButton(
"🎵 Open Quixotic",
web_app=WebAppInfo(url=self.web_app_url)
)]
]
reply_markup = InlineKeyboardMarkup(keyboard)
welcome_text = (
f"👋 Welcome to Quixotic, {user.first_name}!\n\n"
"🎵 Search and download music from SoundCloud\n"
"🚀 Fast MP3 conversion\n"
"📱 Easy-to-use interface\n\n"
"Click the button below to get started!"
)
await context.bot.send_message(
chat_id=chat_id,
text=welcome_text,
reply_markup=reply_markup
)
async def help_command(self, update, context):
"""Handle /help command"""
help_text = (
"🎵 *Quixotic Bot Help*\n\n"
"*Commands:*\n"
"/start - Start the bot and open the music app\n"
"/help - Show this help message\n\n"
"*How to use:*\n"
"1. Click 'Open Quixotic' to launch the web app\n"
"2. Search for your favorite songs\n"
"3. Convert and download as MP3\n"
"4. Music files will be sent directly to this chat\n\n"
"*Features:*\n"
"• SoundCloud music search\n"
"• High-quality MP3 conversion\n"
"• Fast downloads\n"
"• Search history tracking\n\n"
"Enjoy your music! 🎶"
)
await update.message.reply_text(
help_text,
parse_mode='Markdown'
)
async def handle_message(self, update, context):
"""Handle text messages"""
# For now, just respond with instructions to use the web app
keyboard = [
[InlineKeyboardButton(
"🎵 Open Quixotic",
web_app=WebAppInfo(url=self.web_app_url)
)]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"Use the web app to search and download music! 🎵",
reply_markup=reply_markup
)
async def send_audio_file(self, chat_id: int, audio_url: str, title: str,
performer: Optional[str] = None, thumbnail: Optional[str] = None):
"""Send audio file to user"""
try:
print(f"📤 Sending audio to chat {chat_id}")
# Download the audio file first
async with httpx.AsyncClient() as client:
response = await client.get(audio_url)
response.raise_for_status()
audio_data = response.content
# Send audio
await self.bot.send_audio(
chat_id=chat_id,
audio=audio_data,
title=title,
performer=performer or "Unknown Artist",
duration=None, # Let Telegram figure it out
caption=f"🎵 {title}" + (f" by {performer}" if performer else ""),
thumbnail=thumbnail if thumbnail else None
)
print(f"✅ Audio sent successfully to chat {chat_id}")
except Exception as e:
print(f"❌ Failed to send audio to chat {chat_id}: {e}")
# Send error message
error_message = (
"❌ Failed to send audio file. "
"The file might be too large or temporarily unavailable."
)
try:
await self.bot.send_message(chat_id=chat_id, text=error_message)
except Exception as msg_error:
print(f"❌ Failed to send error message: {msg_error}")
raise e
async def start_polling(self):
"""Start bot polling"""
print("🤖 Starting bot polling...")
await self.application.initialize()
await self.application.start()
await self.application.updater.start_polling()
async def close(self):
"""Close bot application"""
if self.application:
await self.application.stop()
await self.application.shutdown()
print("🤖 Bot closed")