From eb126433961243df1445d5e0b51a82927aaaddbb Mon Sep 17 00:00:00 2001 From: DerrtSML <93052047+DerrtSML@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:09:23 +0300 Subject: [PATCH] Update bot.py --- bot.py | 123 +++++++++++---------------------------------------------- 1 file changed, 23 insertions(+), 100 deletions(-) diff --git a/bot.py b/bot.py index 95af1c5..bf9e61a 100644 --- a/bot.py +++ b/bot.py @@ -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 (ОБНОВЛЕНО для кнопок старт/стоп с учетом 'Stopped' и 'Completed') --- +# --- Команда /status (ОБНОВЛЕНО с учетом точных статусов) --- 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.") @@ -120,6 +120,8 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: return for torrent in torrents: + # logger.info(f"Torrent '{torrent.name}' has state: '{torrent.state}'") # Временное логирование удалено + download_speed = torrent.dlspeed / (1024 * 1024) if torrent.dlspeed >= (1024 * 1024) else torrent.dlspeed / 1024 upload_speed = torrent.upspeed / (1024 * 1024) if torrent.upspeed >= (1024 * 1024) else torrent.upspeed / 1024 @@ -144,7 +146,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,18 +154,23 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: ) keyboard = [] - active_states = ['downloading', 'stalledDL', 'uploading', 'checkingQT', 'queuedDL', 'checkingUP', 'queuedUP'] - # Включили 'Stopped' и 'Completed' в список состояний, для которых предлагаем кнопку "Запустить" - paused_states = ['pausedDL', 'pausedUP', 'Stopped', 'Completed'] + active_states = [ + 'downloading', 'stalledDL', 'uploading', 'checkingQT', + 'queuedDL', 'checkingUP', 'queuedUP' + ] + paused_states = [ + 'pausedDL', 'pausedUP', 'stoppedUP', 'stoppedDL' # Корректные статусы из логов + ] if torrent.state in active_states: keyboard.append(InlineKeyboardButton("🔴 Остановить", callback_data=f"stop_hash_{torrent.hash}")) elif torrent.state in paused_states: keyboard.append(InlineKeyboardButton("▶️ Запустить", callback_data=f"start_hash_{torrent.hash}")) elif torrent.state == 'metaDL': - pass + pass # Не предлагаем кнопок, пока не начнется фактическая загрузка else: - 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 @@ -219,7 +226,7 @@ async def stop_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TY logger.error(f"An unexpected error occurred during torrent pausing: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") -# --- НОВАЯ функция: Обработка кнопки "Запустить торрент" --- +# --- Обработка кнопки "Запустить торрент" --- async def start_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: query = update.callback_query await query.answer() @@ -242,94 +249,7 @@ async def start_torrent_callback(update: Update, context: ContextTypes.DEFAULT_T except Exception as e: logger.error(f"An unexpected error occurred during torrent resuming: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") -# --- Команда /status (добавляем логирование) --- -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.") - return - logger.info(f"Received /status command from {update.effective_user.id}") - - if not init_qbittorrent_client(): - await update.message.reply_text( - "Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера." - ) - return - - try: - torrents = qb.torrents_info() - if not torrents: - await update.message.reply_text("Загрузок не найдено.") - return - - for torrent in torrents: - # --- ВРЕМЕННОЕ ЛОГИРОВАНИЕ --- - logger.info(f"Torrent '{torrent.name}' has state: '{torrent.state}'") - # --- КОНЕЦ ВРЕМЕННОГО ЛОГИРОВАНИЯ --- - - download_speed = torrent.dlspeed / (1024 * 1024) if torrent.dlspeed >= (1024 * 1024) else torrent.dlspeed / 1024 - upload_speed = torrent.upspeed / (1024 * 1024) if torrent.upspeed >= (1024 * 1024) else torrent.upspeed / 1024 - - dl_unit = "MB/s" if torrent.dlspeed >= (1024 * 1024) else "KB/s" - up_unit = "MB/s" if torrent.upspeed >= (1024 * 1024) else "KB/s" - - eta_str = "" - if torrent.eta == 8640000: - eta_str = "∞" - elif torrent.eta > 0: - hours, remainder = divmod(torrent.eta, 3600) - minutes, seconds = divmod(remainder, 60) - if hours > 0: - eta_str = f"{int(hours)}ч {int(minutes)}мин" - elif minutes > 0: - eta_str = f"{int(minutes)}мин {int(seconds)}с" - else: - eta_str = f"{int(seconds)}с" - else: - eta_str = "Завершено" - - - message_text = ( - f"📊 *{torrent.name}*\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" - f" Размер: {(torrent.size / (1024*1024*1024)):.2f} ГБ" - ) - - keyboard = [] - active_states = ['downloading', 'stalledDL', 'uploading', 'checkingQT', 'queuedDL', 'checkingUP', 'queuedUP'] - # Здесь пока не меняем, чтобы увидеть, что попадет в "else" - 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 in paused_states: - keyboard.append(InlineKeyboardButton("▶️ Запустить", callback_data=f"start_hash_{torrent.hash}")) - elif torrent.state == 'metaDL': - pass - else: - # Если торрент не в активных и не в явных "пауза/остановлено", то "Инфо" - 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", - reply_markup=reply_markup - ) - - except APIError as e: - logger.error(f"Error getting torrent status: {e}") - await update.message.reply_text(f"Ошибка при получении статуса торрентов: {e}") - except Exception as e: - logger.error(f"An unexpected error occurred in status command: {e}") - await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}") - -# ... (Остальной код бота без изменений) ... # --- Обработка magnet-ссылок и URL --- async def handle_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: @@ -393,15 +313,17 @@ async def send_directory_options(query, context): try: available_paths = [ qb.app.default_save_path, - "/mnt/user/downloads/movies", # ЗАМЕНИТЕ НА СВОИ АКТУАЛЬНЫЕ ПУТИ - "/mnt/user/downloads/tv-shows", - "/var/lib/qbittorrent/data/completed", + "/share/Data/Films", # ЗАМЕНИТЕ НА СВОИ АКТУАЛЬНЫЕ ПУТИ + "/share/Data/Serials", + "/share/Data/torrents", ] + # Убедимся, что пути уникальны и отсортированы available_paths = sorted(list(set([p.replace(os.sep, '/') for p in available_paths if p]))) directory_keyboard = [] for path in available_paths: + # Отображаем только имя папки, если путь слишком длинный display_path = os.path.basename(path) if len(path) > 30 else path directory_keyboard.append([InlineKeyboardButton(display_path, callback_data=f"select_dir_{path}")]) @@ -450,6 +372,7 @@ async def select_directory_callback(update: Update, context: ContextTypes.DEFAUL f"Категория: {category or 'Без категории'}\n" f"Директория: {selected_directory}" ) + # Очищаем данные пользователя после успешного добавления if 'current_torrent_url' in context.user_data: del context.user_data['current_torrent_url'] if 'selected_category' in context.user_data: @@ -476,7 +399,7 @@ async def unknown_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> logger.info(f"Received unknown command: {update.message.text} from {update.effective_user.id}") await update.message.reply_text("Извините, я не понял эту команду.") -# --- Обработчик для любого другого текста (для отладки) --- +# --- Обработчик для любого другого текста --- async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: if update.message is None: logger.warning(f"Received non-text update in echo handler: {update}") @@ -496,7 +419,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)) # --- Добавление обработчиков сообщений ---