""" Callback button handling """ from pyrogram import Client from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton from pyrogram.handlers import CallbackQueryHandler from pyrogram.errors import MessageNotModified from bot.modules.access_control.auth import is_authorized, is_admin, is_owner from bot.modules.message_handler.commands import get_start_keyboard import logging logger = logging.getLogger(__name__) async def callback_handler(client: Client, callback_query: CallbackQuery): """Handle callback queries""" user_id = callback_query.from_user.id data = callback_query.data # Check authorization if not await is_authorized(user_id): await callback_query.answer("❌ У вас нет доступа к этому боту", show_alert=True) return # Handle different callback data if data == "back": # Return to main menu welcome_text = ( "👋 **Привет! Я бот для загрузки медиа-файлов.**\n\n" "📥 **Что я умею:**\n" "• Загружать видео с YouTube, Instagram и других платформ\n" "• Загружать файлы по прямым ссылкам\n" "• Отправлять файлы вам в Telegram\n\n" "**Как использовать:**\n" "Просто отправьте мне ссылку на видео или файл, и я загружу его для вас!\n\n" "Используйте кнопки ниже для управления:" ) keyboard = await get_start_keyboard(user_id) await callback_query.edit_message_text(welcome_text, reply_markup=keyboard) await callback_query.answer() elif data == "help": # Show help help_text = ( "👋 **Привет! Рад помочь!**\n\n" "🎯 **Как начать работу:**\n" "Это очень просто! Просто отправьте мне ссылку на видео или файл, и я сразу начну загрузку.\n\n" "📥 **Что я умею загружать:**\n" "• 🎬 Видео с YouTube, Instagram, TikTok и других платформ\n" "• 📁 Файлы по прямым ссылкам\n" "• 🎵 Аудио и музыку\n" "• 📸 Изображения и фото\n\n" "⌨️ **Основные команды:**\n" "• `/start` - Открыть главное меню с кнопками\n" "• `/help` - Показать эту справку\n" "• `/status` - Посмотреть статус ваших загрузок\n\n" "💡 **Совет:** Используйте кнопки в главном меню для быстрого доступа к функциям!" ) if await is_admin(user_id): help_text += ( "\n\n" "👑 **Команды для администраторов:**\n" "• `/adduser ` - Добавить нового пользователя\n" "• `/blockuser ` - Заблокировать пользователя\n" "• `/unblockuser ` - Разблокировать пользователя\n" "• `/listusers` - Посмотреть список всех пользователей\n\n" "💼 **Управление администраторами:**\n" "• `/addadmin ` - Назначить администратора\n" "• `/removeadmin ` - Снять права администратора\n" "• `/listadmins` - Список всех администраторов" ) keyboard = InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 Назад", callback_data="back") ]]) await callback_query.edit_message_text(help_text, reply_markup=keyboard) await callback_query.answer() elif data == "status": # Show task status from bot.modules.task_scheduler.monitor import get_user_tasks_status from bot.modules.task_scheduler.queue import TaskStatus tasks = await get_user_tasks_status(user_id) active_tasks = [t for t in tasks if t.get('status') in ['pending', 'processing']] completed = [t for t in tasks if t.get('status') == 'completed'] failed = [t for t in tasks if t.get('status') == 'failed'] status_text = ( "📊 **Статус задач:**\n\n" f"⏳ Активных задач: {len(active_tasks)}\n" f"✅ Завершено: {len(completed)}\n" f"❌ Ошибок: {len(failed)}\n\n" ) if active_tasks: status_text += "**Активные задачи:**\n" for task in active_tasks[:5]: # Show first 5 task_id = task.get('id') progress = task.get('progress', 0) status_text += f"• #{task_id} - {progress}%\n" if len(active_tasks) > 5: status_text += f"... и еще {len(active_tasks) - 5}\n" status_text += "\n💡 Используйте `/cancel ` для отмены" keyboard = InlineKeyboardMarkup([[ InlineKeyboardButton("🔄 Обновить", callback_data="status"), InlineKeyboardButton("🔙 Назад", callback_data="back") ]]) try: await callback_query.edit_message_text(status_text, reply_markup=keyboard) await callback_query.answer("✅ Статус обновлен") except MessageNotModified: # If text didn't change, just answer callback await callback_query.answer("✅ Статус актуален") elif data == "download": # Download information download_text = ( "📥 **Загрузка файлов:**\n\n" "**Поддерживаемые источники:**\n" "• YouTube (видео, плейлисты)\n" "• Instagram (посты, истории)\n" "• Прямые ссылки на файлы\n" "• Другие платформы через yt-dlp\n\n" "**Как использовать:**\n" "Просто отправьте мне ссылку на видео или файл, и я начну загрузку!\n\n" "Примеры:\n" "• https://www.youtube.com/watch?v=...\n" "• https://www.instagram.com/p/...\n" "• https://example.com/file.mp4" ) keyboard = InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 Назад", callback_data="back") ]]) await callback_query.edit_message_text(download_text, reply_markup=keyboard) await callback_query.answer() elif data == "admin_users": # User management (admin only) if not await is_admin(user_id): await callback_query.answer("❌ Только для администраторов", show_alert=True) return # Determine user status is_owner_user = await is_owner(user_id) # Form text and buttons depending on status if is_owner_user: # Main admin - full functionality users_text = ( "👥 **Управление пользователями:**\n\n" "**Управление пользователями:**\n" "• /adduser - Добавить пользователя\n" "• /blockuser - Заблокировать пользователя\n" "• /unblockuser - Разблокировать пользователя\n" "• /listusers - Список всех пользователей\n\n" "**Управление администраторами:**\n" "• /addadmin - Назначить администратора\n" "• /removeadmin - Снять права администратора\n" "• /listadmins - Список всех администраторов\n\n" "⚠️ **Внимание:** Вы не можете снять права администратора у самого себя." ) else: # Regular administrator - only user management users_text = ( "👥 **Управление пользователями:**\n\n" "**Доступные команды:**\n" "• /adduser - Добавить пользователя\n" "• /blockuser - Заблокировать пользователя\n" "• /unblockuser - Разблокировать пользователя\n" "• /listusers - Список всех пользователей\n\n" "_Управление через веб-интерфейс будет доступно позже_" ) keyboard = InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 Назад", callback_data="back") ]]) await callback_query.edit_message_text(users_text, reply_markup=keyboard) await callback_query.answer() elif data == "admin_stats": # Statistics (admin only) if not await is_admin(user_id): await callback_query.answer("❌ Только для администраторов", show_alert=True) return stats_text = ( "📈 **Статистика:**\n\n" "👥 Всего пользователей: 0\n" "👑 Администраторов: 0\n" "📥 Всего загрузок: 0\n" "✅ Успешных: 0\n" "❌ Ошибок: 0\n\n" "_Статистика будет реализована в следующем этапе_" ) keyboard = InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 Назад", callback_data="back") ]]) await callback_query.edit_message_text(stats_text, reply_markup=keyboard) await callback_query.answer() elif data.startswith("video_select:"): # Handle video selection from webpage video_url = data.replace("video_select:", "", 1) # Create task for selected video try: from bot.modules.task_scheduler.queue import task_queue, Task, TaskStatus from bot.modules.task_scheduler.executor import task_executor, set_app_client from bot.utils.helpers import generate_unique_task_id from shared.database.models import Task as DBTask from shared.database.session import get_async_session_local from shared.database.user_helpers import ensure_user_exists from datetime import datetime from sqlalchemy.exc import IntegrityError from bot.modules.task_scheduler.executor import set_task_message user_id = callback_query.from_user.id # Check concurrent tasks count from bot.config import settings active_tasks_count = await task_queue.get_user_active_tasks_count(user_id) if active_tasks_count >= settings.MAX_CONCURRENT_TASKS: await callback_query.answer( f"❌ Превышен лимит одновременных задач ({settings.MAX_CONCURRENT_TASKS})", show_alert=True ) return # Generate task_id task_id = generate_unique_task_id() existing_task = await task_queue.get_task_by_id(task_id) max_retries = 10 retries = 0 while existing_task and retries < max_retries: task_id = generate_unique_task_id() existing_task = await task_queue.get_task_by_id(task_id) retries += 1 if existing_task: await callback_query.answer("❌ Ошибка при создании задачи", show_alert=True) return # Create task task = Task( id=task_id, user_id=user_id, task_type="download", url=video_url, status=TaskStatus.PENDING ) # Save to database try: async with get_async_session_local()() as session: await ensure_user_exists(user_id, session) db_task = DBTask( id=task_id, user_id=user_id, task_type=task.task_type, status=task.status.value, url=task.url, progress=0, created_at=datetime.utcnow(), updated_at=datetime.utcnow() ) session.add(db_task) await session.commit() except Exception as e: logger.error(f"Error saving task to database: {e}", exc_info=True) await callback_query.answer("❌ Ошибка при создании задачи", show_alert=True) return # Add to queue success = await task_queue.add_task(task, check_duplicate_url=True) if not success: try: async with get_async_session_local()() as session: db_task = await session.get(DBTask, task_id) if db_task: await session.delete(db_task) await session.commit() except Exception as e: logger.error(f"Error deleting task from database: {e}") await callback_query.answer("⚠️ Задача с этим URL уже обрабатывается", show_alert=True) return # Start executor if needed set_app_client(client) if not task_executor._running: await task_executor.start() # Send status message status_message = await callback_query.message.reply( f"📥 **Загрузка начата**\n\n" f"🔗 {video_url[:50]}...\n\n" f"📊 Прогресс: **0%**\n" f"⏳ Ожидание начала загрузки..." ) set_task_message(task_id, status_message.id) await callback_query.answer("✅ Загрузка начата") # Update original message to show selection try: await callback_query.edit_message_reply_markup( reply_markup=None # Remove buttons ) original_text = callback_query.message.text or "" await callback_query.message.edit_text( original_text + f"\n\n✅ Выбрано: {video_url[:50]}..." ) except Exception as e: logger.debug(f"Failed to update selection message: {e}") except Exception as e: logger.error(f"Error handling video selection: {e}", exc_info=True) await callback_query.answer("❌ Ошибка при запуске загрузки", show_alert=True) else: await callback_query.answer("❓ Неизвестная команда") def register_callbacks(app: Client): """Register all callback handlers""" app.add_handler(CallbackQueryHandler(callback_handler)) logger.info("Callback handlers registered")