Update bot.py

This commit is contained in:
DerrtSML 2025-06-23 19:44:02 +03:00 committed by GitHub
parent 4f5fbf9a39
commit 7e35b1eaf1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

55
bot.py
View File

@ -80,7 +80,7 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"Используй /help для списка команд." "Используй /help для списка команд."
) )
# --- Команда /help (исправленная функция) --- # --- Команда /help (без Markdown) ---
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if update.message is None: if update.message is None:
logger.warning("Received an update without a message object in help handler.") logger.warning("Received an update without a message object in help handler.")
@ -88,20 +88,20 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
logger.info(f"Received /help command from {update.effective_user.id}") logger.info(f"Received /help command from {update.effective_user.id}")
# Здесь Markdown используется, parse_mode="Markdown" необходим # Здесь Markdown был удален для отладки
help_text = ( help_text = (
"Вот список доступных команд:\n\n" "Вот список доступных команд:\n\n"
"**/start** - Начать работу с ботом и проверить подключение к qBittorrent.\n" "/start - Начать работу с ботом и проверить подключение к qBittorrent.\n"
"**/status** - Показать текущий статус всех активных загрузок.\n" "/status - Показать текущий статус всех активных загрузок.\n"
"**/stop_torrent** - Выбрать и остановить загрузку торрента.\n" "/stop_torrent - Выбрать и остановить загрузку торрента.\n"
"**/help** - Показать это справочное сообщение.\n\n" "/help - Показать это справочное сообщение.\n\n"
"Также вы можете отправить мне *magnet-ссылку* или *URL torrent-файла* " "Также вы можете отправить мне magnet-ссылку или URL torrent-файла "
"для добавления загрузки. Бот предложит выбрать категорию и директорию." "для добавления загрузки. Бот предложит выбрать категорию и директорию."
) )
await update.message.reply_text(help_text, parse_mode="Markdown") await update.message.reply_text(help_text) # parse_mode="Markdown" удален
# --- Команда /status --- # --- Команда /status (без Markdown) ---
async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if update.message is None: if update.message is None:
logger.warning("Received an update without a message object in status handler.") logger.warning("Received an update without a message object in status handler.")
@ -118,7 +118,6 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
try: try:
torrents = qb.torrents_info() torrents = qb.torrents_info()
if not torrents: if not torrents:
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text("Загрузок не найдено.") await update.message.reply_text("Загрузок не найдено.")
return return
@ -146,9 +145,9 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
eta_str = "Завершено" eta_str = "Завершено"
# Здесь Markdown используется, поэтому важно, чтобы он был корректным # Здесь Markdown был удален для отладки (включая *)
status_messages.append( status_messages.append(
f"📊 *{torrent.name}*\n" f"📊 {torrent.name}\n"
f" Состояние: {torrent.state}\n" f" Состояние: {torrent.state}\n"
f" Прогресс: {torrent.progress:.2%}\n" f" Прогресс: {torrent.progress:.2%}\n"
f" ⬇️ {download_speed:.2f} {dl_unit} ⬆️ {upload_speed:.2f} {up_unit}\n" f" ⬇️ {download_speed:.2f} {dl_unit} ⬆️ {upload_speed:.2f} {up_unit}\n"
@ -157,16 +156,14 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
) )
await update.message.reply_text( await update.message.reply_text(
"\n\n".join(status_messages), parse_mode="Markdown" "\n\n".join(status_messages)
) ) # parse_mode="Markdown" удален
except APIError as e: except APIError as e:
logger.error(f"Error getting torrent status: {e}") logger.error(f"Error getting torrent status: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Ошибка при получении статуса торрентов: {e}") await update.message.reply_text(f"Ошибка при получении статуса торрентов: {e}")
except Exception as e: except Exception as e:
logger.error(f"An unexpected error occurred in status command: {e}") logger.error(f"An unexpected error occurred in status command: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}") await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}")
# --- Команда /stop_torrent --- # --- Команда /stop_torrent ---
@ -186,7 +183,6 @@ async def stop_torrent(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
try: try:
torrents = qb.torrents_info(status_filter='downloading') torrents = qb.torrents_info(status_filter='downloading')
if not torrents: if not torrents:
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text("Нет активных загрузок для остановки.") await update.message.reply_text("Нет активных загрузок для остановки.")
return return
@ -199,16 +195,13 @@ async def stop_torrent(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
keyboard.append([InlineKeyboardButton(display_name, callback_data=f"stop_hash_{torrent.hash}")]) keyboard.append([InlineKeyboardButton(display_name, callback_data=f"stop_hash_{torrent.hash}")])
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text("Выберите торрент для остановки:", reply_markup=reply_markup) await update.message.reply_text("Выберите торрент для остановки:", reply_markup=reply_markup)
except APIError as e: except APIError as e:
logger.error(f"Error fetching torrents for stopping: {e}") logger.error(f"Error fetching torrents for stopping: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Ошибка при получении списка торрентов для остановки: {e}") await update.message.reply_text(f"Ошибка при получении списка торрентов для остановки: {e}")
except Exception as e: except Exception as e:
logger.error(f"An unexpected error occurred in stop_torrent command: {e}") logger.error(f"An unexpected error occurred in stop_torrent command: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}") await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}")
# --- Обработка кнопки "Остановить торрент" --- # --- Обработка кнопки "Остановить торрент" ---
@ -220,7 +213,6 @@ async def stop_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TY
logger.info(f"Attempting to stop torrent with hash: {torrent_hash}") logger.info(f"Attempting to stop torrent with hash: {torrent_hash}")
if not init_qbittorrent_client(): if not init_qbittorrent_client():
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text( await query.edit_message_text(
"Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера." "Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера."
) )
@ -228,15 +220,12 @@ async def stop_torrent_callback(update: Update, context: ContextTypes.DEFAULT_TY
try: try:
qb.torrents_stop(torrent_hashes=torrent_hash) qb.torrents_stop(torrent_hashes=torrent_hash)
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Торрент ({torrent_hash[:6]}...) успешно остановлен.") await query.edit_message_text(f"Торрент ({torrent_hash[:6]}...) успешно остановлен.")
except APIError as e: except APIError as e:
logger.error(f"Error stopping torrent {torrent_hash}: {e}") logger.error(f"Error stopping torrent {torrent_hash}: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Ошибка при остановке торрента: {e}") await query.edit_message_text(f"Ошибка при остановке торрента: {e}")
except Exception as 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 stopping: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}")
# --- Обработка magnet-ссылок и URL --- # --- Обработка magnet-ссылок и URL ---
@ -249,7 +238,6 @@ async def handle_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None
logger.info(f"Received URL/Magnet: {text} from {update.effective_user.id}") logger.info(f"Received URL/Magnet: {text} from {update.effective_user.id}")
if not init_qbittorrent_client(): if not init_qbittorrent_client():
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text( await update.message.reply_text(
"Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера." "Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера."
) )
@ -266,16 +254,13 @@ async def handle_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None
category_keyboard.append([InlineKeyboardButton("Без категории", callback_data="select_category_no_category")]) category_keyboard.append([InlineKeyboardButton("Без категории", callback_data="select_category_no_category")])
reply_markup = InlineKeyboardMarkup(category_keyboard) reply_markup = InlineKeyboardMarkup(category_keyboard)
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text('Выберите категорию для загрузки:', reply_markup=reply_markup) await update.message.reply_text('Выберите категорию для загрузки:', reply_markup=reply_markup)
except APIError as e: except APIError as e:
logger.error(f"Error fetching categories: {e}") logger.error(f"Error fetching categories: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Ошибка при получении категорий: {e}") await update.message.reply_text(f"Ошибка при получении категорий: {e}")
except Exception as e: except Exception as e:
logger.error(f"An unexpected error occurred in handle_url: {e}") logger.error(f"An unexpected error occurred in handle_url: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}") await update.message.reply_text(f"Произошла непредвиденная ошибка: {e}")
@ -291,14 +276,12 @@ async def select_category_callback(update: Update, context: ContextTypes.DEFAULT
context.user_data['selected_category'] = selected_category context.user_data['selected_category'] = selected_category
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text("Выберите директорию загрузки:") await query.edit_message_text("Выберите директорию загрузки:")
await send_directory_options(query, context) await send_directory_options(query, context)
# --- Отправка опций директорий --- # --- Отправка опций директорий ---
async def send_directory_options(query, context): async def send_directory_options(query, context):
if not init_qbittorrent_client(): if not init_qbittorrent_client():
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text( await query.edit_message_text(
"Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера." "Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера."
) )
@ -320,17 +303,13 @@ async def send_directory_options(query, context):
directory_keyboard.append([InlineKeyboardButton(display_path, callback_data=f"select_dir_{path}")]) directory_keyboard.append([InlineKeyboardButton(display_path, callback_data=f"select_dir_{path}")])
reply_markup = InlineKeyboardMarkup(directory_keyboard) reply_markup = InlineKeyboardMarkup(directory_keyboard)
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
# edit_message_reply_markup не принимает parse_mode
await query.edit_message_reply_markup(reply_markup=reply_markup) await query.edit_message_reply_markup(reply_markup=reply_markup)
except APIError as e: except APIError as e:
logger.error(f"Error fetching default save path: {e}") logger.error(f"Error fetching default save path: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Ошибка при получении директорий сохранения: {e}") await query.edit_message_text(f"Ошибка при получении директорий сохранения: {e}")
except Exception as e: except Exception as e:
logger.error(f"An unexpected error occurred in send_directory_options: {e}") logger.error(f"An unexpected error occurred in send_directory_options: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}")
@ -348,12 +327,10 @@ async def select_directory_callback(update: Update, context: ContextTypes.DEFAUL
category = context.user_data.get('selected_category') category = context.user_data.get('selected_category')
if not torrent_url: if not torrent_url:
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text("Ошибка: URL торрента не найден. Пожалуйста, попробуйте снова.") await query.edit_message_text("Ошибка: URL торрента не найден. Пожалуйста, попробуйте снова.")
return return
if not init_qbittorrent_client(): if not init_qbittorrent_client():
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text( await query.edit_message_text(
"Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера." "Не удалось подключиться к qBittorrent. Проверьте переменные окружения и доступность сервера."
) )
@ -365,7 +342,6 @@ async def select_directory_callback(update: Update, context: ContextTypes.DEFAUL
category=category, category=category,
save_path=selected_directory save_path=selected_directory
) )
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text( await query.edit_message_text(
f"Торрент успешно добавлен в qBittorrent.\n" f"Торрент успешно добавлен в qBittorrent.\n"
f"Категория: {category or 'Без категории'}\n" f"Категория: {category or 'Без категории'}\n"
@ -377,11 +353,9 @@ async def select_directory_callback(update: Update, context: ContextTypes.DEFAUL
del context.user_data['selected_category'] del context.user_data['selected_category']
except APIError as e: except APIError as e:
logger.error(f"Error adding torrent with path: {e}") logger.error(f"Error adding torrent with path: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Ошибка при добавлении торрента: {e}") await query.edit_message_text(f"Ошибка при добавлении торрента: {e}")
except Exception as e: except Exception as e:
logger.error(f"An unexpected error occurred during torrent addition with path: {e}") logger.error(f"An unexpected error occurred during torrent addition with path: {e}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}") await query.edit_message_text(f"Произошла непредвиденная ошибка: {e}")
@ -389,7 +363,6 @@ async def select_directory_callback(update: Update, context: ContextTypes.DEFAUL
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None: async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.error(f"Exception while handling an update: {context.error}") logger.error(f"Exception while handling an update: {context.error}")
if update and update.effective_message: if update and update.effective_message:
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.effective_message.reply_text(f"Произошла внутренняя ошибка бота: {context.error}") await update.effective_message.reply_text(f"Произошла внутренняя ошибка бота: {context.error}")
# --- Обработчик для неизвестных команд --- # --- Обработчик для неизвестных команд ---
@ -398,7 +371,6 @@ async def unknown_command(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
logger.warning("Received an unknown command update without a message object.") logger.warning("Received an unknown command update without a message object.")
return return
logger.info(f"Received unknown command: {update.message.text} from {update.effective_user.id}") logger.info(f"Received unknown command: {update.message.text} from {update.effective_user.id}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text("Извините, я не понял эту команду.") await update.message.reply_text("Извините, я не понял эту команду.")
# --- Обработчик для любого другого текста (для отладки) --- # --- Обработчик для любого другого текста (для отладки) ---
@ -407,7 +379,6 @@ async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.warning(f"Received non-text update in echo handler: {update}") logger.warning(f"Received non-text update in echo handler: {update}")
return return
logger.info(f"Received non-command text: {update.message.text} from {update.effective_user.id}") logger.info(f"Received non-command text: {update.message.text} from {update.effective_user.id}")
# В этом сообщении нет Markdown, поэтому parse_mode не нужен
await update.message.reply_text(f"Вы сказали: {update.message.text}") await update.message.reply_text(f"Вы сказали: {update.message.text}")