# handlers.py import os import asyncio import logging from typing import List from hydrogram import Client, filters from hydrogram.types import Message from hydrogram.errors import FloodWait, RPCError from hydrogram.handlers import MessageHandler # Explicit import for add_handler from config import Config from utils import is_admin from processing import process_images_sync from main import executor # Import executor from main.py logger = logging.getLogger(__name__) async def handle_photo_message_impl(client: Client, message: Message): user = message.from_user user_id = user.id user_info = f"user_id={user_id}" + (f", username={user.username}" if user.username else "") caption = message.caption if message.caption else "" message_id = message.id chat_id = message.chat.id logger.info(f"ADMIN ACTION (Bot): Received photo with caption from {user_info} (msg_id={message_id}).") temp_user_image_path = os.path.join(Config.OUTPUT_DIR, f"bot_user_{user_id}_{message_id}.jpg") file_downloaded = False processing_status_message = None try: if not message.photo: return download_start_time = asyncio.get_running_loop().time() logger.info(f"Attempting download photo (file_id: {message.photo.file_id})...") downloaded_path = await client.download_media(message.photo.file_id, file_name=temp_user_image_path) if downloaded_path and os.path.exists(downloaded_path): download_time = asyncio.get_running_loop().time() - download_start_time logger.info(f"Photo downloaded to '{downloaded_path}' in {download_time:.2f}s.") temp_user_image_path = downloaded_path file_downloaded = True else: logger.error(f"Download failed or file not found: '{temp_user_image_path}'. Path: {downloaded_path}") await message.reply_text("❌ Internal error after download attempt.") return except FloodWait as e: logger.warning(f"Flood wait: {e.value}s during download (msg_id={message_id}).") await asyncio.sleep(e.value + 2) await message.reply_text(f"⏳ Telegram limits hit. Wait {e.value}s & try again.") return except RPCError as e: logger.error(f"RPC error downloading photo (msg_id={message_id}): {e}", exc_info=True) await message.reply_text("❌ Telegram API error downloading image.") return except Exception as e: logger.error(f"Unexpected error downloading photo (msg_id={message_id}): {e}", exc_info=True) await message.reply_text("❌ Unexpected error downloading image.") return try: processing_status_message = await message.reply_text("⏳ Processing your image...", quote=True) except Exception as e: logger.warning(f"Could not send 'Processing...' message: {e}") message_to_delete_id = processing_status_message.id if processing_status_message else None loop = asyncio.get_running_loop() generated_images: List[str] = [] processing_failed = False try: logger.info(f"Submitting image processing for '{os.path.basename(temp_user_image_path)}'") generated_images = await loop.run_in_executor( executor, process_images_sync, temp_user_image_path, caption ) except Exception as e: processing_failed = True logger.error(f"Error during image processing executor call: {e}", exc_info=True) error_message = "❌ Unexpected error during processing." if message_to_delete_id: try: await client.edit_message_text(chat_id, message_to_delete_id, error_message) except Exception as edit_e: logger.warning(f"Could not edit status msg: {edit_e}") message_to_delete_id = None else: await message.reply_text(error_message) if message_to_delete_id: try: await client.delete_messages(chat_id, message_to_delete_id) except Exception as del_e: logger.warning(f"Could not delete status msg: {del_e}") if not processing_failed: if not generated_images: await message.reply_text("😕 No styled images generated. Check templates?") else: logger.info(f"Sending {len(generated_images)} images for message {message_id}.") for i, img_path in enumerate(generated_images): if not os.path.exists(img_path): continue caption_text = f"Style {i+1}" if len(generated_images) > 1 else "🖼️ Styled image:" try: await message.reply_photo(photo=img_path, caption=caption_text, quote=True) except Exception as e: logger.error(f"Error sending photo '{os.path.basename(img_path)}': {e}", exc_info=True) finally: try: if os.path.exists(img_path): os.remove(img_path) except OSError as e: logger.error(f"Error deleting file '{img_path}': {e}") try: if file_downloaded and os.path.exists(temp_user_image_path): os.remove(temp_user_image_path) except OSError as e: logger.error(f"Error cleaning user image '{temp_user_image_path}': {e}") def register_handlers(app: Client): admin_photo_filter = filters.photo & filters.caption & filters.private & is_admin app.add_handler(MessageHandler(handle_photo_message_impl, filters=admin_photo_filter)) logger.info("Registered admin photo handler for bot.")