# utils/telegram_utils.py import os import json import httpx # Sử dụng httpx để gửi request bất đồng bộ # Lấy URL của Cloudflare Worker từ biến môi trường (Secrets) WORKER_URL = os.environ.get("WORKER_URL") async def send_telegram_message(chat_id, text, reply_markup=None): """Gửi tin nhắn văn bản qua Cloudflare Worker.""" if not WORKER_URL: print("ERROR: WORKER_URL is not set!") return False url = f"{WORKER_URL}" # Dùng Markdown để định dạng nếu Worker hỗ trợ payload = {'action': 'sendMessage', 'chat_id': str(chat_id), 'text': text, 'parse_mode': 'Markdown'} if reply_markup: # Đảm bảo reply_markup là JSON string nếu nó là dict payload['reply_markup'] = json.dumps(reply_markup) if isinstance(reply_markup, dict) else reply_markup try: async with httpx.AsyncClient() as client: response = await client.post(url, json=payload, timeout=60) response.raise_for_status() # Báo lỗi nếu request thất bại (status code >= 400) # print(f"Sent message to {chat_id} via worker: {response.json()}") # Tùy chọn: log lại return True except httpx.RequestError as e: print(f"ERROR sending message via worker (RequestError): {e}") except httpx.HTTPStatusError as e: print(f"ERROR sending message via worker (HTTPStatusError {e.response.status_code}): {e.response.text}") except Exception as e: print(f"ERROR sending message via worker (General): {e}") return False async def send_telegram_video(chat_id, video_path, caption): """Gửi file video qua Cloudflare Worker.""" if not WORKER_URL: print("ERROR: WORKER_URL is not set!") return False url = f"{WORKER_URL}" if not os.path.exists(video_path): print(f"ERROR: Video file not found: {video_path}") # Gửi thông báo lỗi về Telegram nếu file không tồn tại await send_telegram_message(chat_id, f"❌ Lỗi Server: Không tìm thấy file `{os.path.basename(video_path)}` để gửi.") return False # Kiểm tra kích thước file (Tùy chọn, Telegram Bot API thường giới hạn 50MB) file_size_mb = os.path.getsize(video_path) / (1024 * 1024) if file_size_mb > 49.0: # Giới hạn an toàn < 50MB print(f"WARNING: File {video_path} ({file_size_mb:.1f}MB) might be too large for Telegram Bot API.") await send_telegram_message(chat_id, f"⚠️ File `{os.path.basename(video_path)}` ({file_size_mb:.1f}MB) có thể quá lớn để gửi qua bot.") # Bạn có thể chọn trả về False ở đây nếu muốn chặn gửi file lớn # return False # Khi gửi file, payload thường được gửi dưới dạng 'data' (form data), không phải 'json' data_payload = { 'action': 'sendVideo', 'chat_id': str(chat_id), 'caption': caption } try: with open(video_path, 'rb') as video_file: # files={'tên_trường_file': (tên_file, đối_tượng_file, kiểu_mime)} files_payload = { 'video': (os.path.basename(video_path), video_file, 'video/mp4') } async with httpx.AsyncClient() as client: # Dùng data=data_payload và files=files_payload response = await client.post(url, data=data_payload, files=files_payload, timeout=600) # Tăng timeout response.raise_for_status() # print(f"Sent video to {chat_id} via worker: {response.json()}") # Tùy chọn: log lại return True except httpx.RequestError as e: print(f"ERROR sending video via worker (RequestError): {e}") await send_telegram_message(chat_id, f"❌ Lỗi mạng khi gửi file `{os.path.basename(video_path)}`.") except httpx.HTTPStatusError as e: print(f"ERROR sending video via worker (HTTPStatusError {e.response.status_code}): {e.response.text}") await send_telegram_message(chat_id, f"❌ Lỗi từ server khi gửi file `{os.path.basename(video_path)}`: {e.response.status_code}") except Exception as e: print(f"ERROR sending video via worker (General): {e}") await send_telegram_message(chat_id, f"❌ Lỗi không xác định khi gửi file `{os.path.basename(video_path)}`.") return False async def answer_telegram_callback_query(callback_query_id, text="OK"): """Trả lời một callback query qua Worker.""" if not WORKER_URL: print("ERROR: WORKER_URL not set!"); return url = f"{WORKER_URL}" payload = {'action': 'answerCallbackQuery', 'callback_query_id': callback_query_id, 'text': text} try: async with httpx.AsyncClient() as client: response = await client.post(url, json=payload, timeout=30) response.raise_for_status() except Exception as e: print(f"ERROR answering callback query {callback_query_id} via worker: {e}") async def edit_telegram_message_text(chat_id, message_id, text, reply_markup=None): """Sửa nội dung tin nhắn văn bản qua Worker.""" if not WORKER_URL: print("ERROR: WORKER_URL not set!"); return url = f"{WORKER_URL}" payload = {'action': 'editMessageText', 'chat_id': str(chat_id), 'message_id': message_id, 'text': text, 'parse_mode': 'Markdown'} if reply_markup: payload['reply_markup'] = json.dumps(reply_markup) if isinstance(reply_markup, dict) else reply_markup try: async with httpx.AsyncClient() as client: response = await client.post(url, json=payload, timeout=60) response.raise_for_status() except Exception as e: print(f"ERROR editing message {message_id} in chat {chat_id} via worker: {e}") # (Tùy chọn) Thêm các hàm khác nếu cần, ví dụ: delete_telegram_message, edit_telegram_reply_markup # async def delete_telegram_message(chat_id, message_id): ...