diff --git a/bot.py b/bot.py index 64f6f53..6870c6c 100644 --- a/bot.py +++ b/bot.py @@ -90,8 +90,8 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No help_text = ( "Вот список доступных команд:\n\n" "**/start** - Начать работу с ботом и проверить подключение к qBittorrent.\n" - "**/status** - Показать текущий статус всех активных загрузок и управлять ими.\n" # Обновил описание - "**/stop_torrent** - Выбрать и остановить загрузку торрента (устаревает, используйте /status).\n" # Отметил как устаревшую + "**/status** - Показать текущий статус всех активных загрузок и управлять ими.\n" + "**/stop_torrent** - Выбрать и остановить загрузку торрента (устаревает, используйте /status).\n" "**/help** - Показать это справочное сообщение.\n\n" "Также вы можете отправить мне *magnet-ссылку* или *URL torrent-файла* " "для добавления загрузки. Бот предложит выбрать категорию и директорию." @@ -99,7 +99,7 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No await update.message.reply_text(help_text, parse_mode="Markdown") -# --- Команда /status (обновлено для кнопок старт/стоп) --- +# --- Команда /status (ОБНОВЛЕНО для кнопок старт/стоп с учетом 'Stopped' и 'Completed') --- async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: if update.message is None: logger.warning("Received an update without a message object in status handler.") @@ -144,7 +144,7 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: message_text = ( f"📊 *{torrent.name}*\n" - f" Состояние: {torrent.state}\n" + f" Состояние: {torrent.state}\n" # Выводит текущее состояние f" Прогресс: {torrent.progress:.2%}\n" f" ⬇️ {download_speed:.2f} {dl_unit} ⬆️ {upload_speed:.2f} {up_unit}\n" f" ETA: {eta_str}\n" @@ -152,24 +152,22 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: ) keyboard = [] - # Проверяем состояние торрента для отображения нужной кнопки - if torrent.state in ['downloading', 'stalledDL', 'uploading', 'checkingQT', 'queuedDL', 'checkingUP', 'pausedDL', 'queuedUP']: - # Если торрент активен или на паузе (но не в остановленном состоянии "pausedUP"), предлагаем остановить + active_states = ['downloading', 'stalledDL', 'uploading', 'checkingQT', 'queuedDL', 'checkingUP', 'queuedUP'] + # Включили 'Stopped' и 'Completed' в список состояний, для которых предлагаем кнопку "Запустить" + paused_states = ['pausedDL', 'pausedUP', 'Stopped', 'Completed'] + + if torrent.state in active_states: keyboard.append(InlineKeyboardButton("🔴 Остановить", callback_data=f"stop_hash_{torrent.hash}")) - elif torrent.state == 'pausedUP': # Это состояние, когда торрент завершен, но на паузе. - keyboard.append(InlineKeyboardButton("▶️ Запустить", callback_data=f"start_hash_{torrent.hash}")) - elif torrent.state == 'metaDL': # Метаданные загружаются - # Пока не предлагаем кнопок, пока не начнется фактическая загрузка - pass # Можно добавить кнопку "Отменить" позже + elif torrent.state in paused_states: + keyboard.append(InlineKeyboardButton("▶️ Запустить", callback_data=f"start_hash_{torrent.hash}")) + elif torrent.state == 'metaDL': + pass else: - # Для других состояний, таких как 'error', 'missingFiles', 'unknown' - # или для тех, что не подразумевают активного управления через старт/стоп - keyboard.append(InlineKeyboardButton("❓ Неизвестное состояние", callback_data=f"info_hash_{torrent.hash}")) + keyboard.append(InlineKeyboardButton("ℹ️ Инфо", callback_data=f"info_hash_{torrent.hash}")) reply_markup = InlineKeyboardMarkup([keyboard]) if keyboard else None - # Отправляем каждое сообщение о торренте отдельно с его кнопками await update.message.reply_text( message_text, parse_mode="Markdown", @@ -185,7 +183,6 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: # --- Команда /stop_torrent (Теперь это будет устаревшая команда) --- -# Ее можно удалить позже, когда все привыкнут к кнопкам в /status async def stop_torrent(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: if update.message is None: logger.warning("Received an update without a message object in stop_torrent handler.") @@ -196,10 +193,6 @@ async def stop_torrent(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No await update.message.reply_text( "Используйте команду /status для управления торрентами через кнопки 'Запустить' и 'Остановить'." ) - # Если вы хотите полностью убрать эту команду, можете закомментировать или удалить ее - # и убрать из add_handler в main() - # Остальной код этой функции может быть полезен, если вы все же хотите сохранить старый механизм. - # Но для удобства, я предлагаю перенаправить пользователя на /status. # --- Обработка кнопки "Остановить торрент" --- @@ -208,7 +201,7 @@ async def stop_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TY await query.answer() torrent_hash = query.data.replace("stop_hash_", "") - logger.info(f"Attempting to stop torrent with hash: {torrent_hash}") + logger.info(f"Attempting to pause torrent with hash: {torrent_hash}") if not init_qbittorrent_client(): await query.edit_message_text( @@ -217,13 +210,13 @@ async def stop_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TY return try: - qb.torrents_pause(torrent_hashes=torrent_hash) # Используем pause вместо stop для возможности возобновления + qb.torrents_pause(torrent_hashes=torrent_hash) await query.edit_message_text(f"Торрент ({torrent_hash[:6]}...) успешно остановлен (поставлен на паузу).") except APIError as e: - logger.error(f"Error stopping torrent {torrent_hash}: {e}") + logger.error(f"Error pausing torrent {torrent_hash}: {e}") await query.edit_message_text(f"Ошибка при остановке торрента: {e}") except Exception as e: - logger.error(f"An unexpected error occurred during torrent stopping: {e}") + logger.error(f"An unexpected error occurred during torrent pausing: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") # --- НОВАЯ функция: Обработка кнопки "Запустить торрент" --- @@ -232,7 +225,7 @@ async def start_torrent_callback(update: Update, context: ContextTypes.DEFAULT_T await query.answer() torrent_hash = query.data.replace("start_hash_", "") - logger.info(f"Attempting to start torrent with hash: {torrent_hash}") + logger.info(f"Attempting to resume torrent with hash: {torrent_hash}") if not init_qbittorrent_client(): await query.edit_message_text( @@ -244,10 +237,10 @@ async def start_torrent_callback(update: Update, context: ContextTypes.DEFAULT_T qb.torrents_resume(torrent_hashes=torrent_hash) await query.edit_message_text(f"Торрент ({torrent_hash[:6]}...) успешно запущен (возобновлен).") except APIError as e: - logger.error(f"Error starting torrent {torrent_hash}: {e}") + logger.error(f"Error resuming torrent {torrent_hash}: {e}") await query.edit_message_text(f"Ошибка при запуске торрента: {e}") except Exception as e: - logger.error(f"An unexpected error occurred during torrent starting: {e}") + logger.error(f"An unexpected error occurred during torrent resuming: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") @@ -416,7 +409,7 @@ def main() -> None: # --- Добавление обработчиков команд --- application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("status", status)) - application.add_handler(CommandHandler("stop_torrent", stop_torrent)) + application.add_handler(CommandHandler("stop_torrent", stop_torrent)) # Оставляем для перенаправления application.add_handler(CommandHandler("help", help_command)) # --- Добавление обработчиков сообщений --- @@ -429,9 +422,9 @@ def main() -> None: application.add_handler(CallbackQueryHandler(select_category_callback, pattern=r"^select_category_.*")) # Добавляем CallbackQueryHandler для кнопок выбора директории application.add_handler(CallbackQueryHandler(select_directory_callback, pattern=r"^select_dir_.*")) - # ОБНОВЛЕНИЕ: CallbackQueryHandler для кнопок остановки торрентов + # CallbackQueryHandler для кнопок остановки торрентов application.add_handler(CallbackQueryHandler(stop_torrent_callback, pattern=r"^stop_hash_.*")) - # НОВЫЙ CallbackQueryHandler для кнопок запуска торрентов + # CallbackQueryHandler для кнопок запуска торрентов application.add_handler(CallbackQueryHandler(start_torrent_callback, pattern=r"^start_hash_.*"))