testdouy / utils /telegram_utils.py
geopromini's picture
Create utils/telegram_utils.py
1a0daa2 verified
# 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): ...