Add upload images
This commit is contained in:
@@ -54,6 +54,209 @@ class TelegramNotifier:
|
||||
logger.error(f"Error sending Telegram message: {e}")
|
||||
return False
|
||||
|
||||
async def send_photo(
|
||||
self,
|
||||
chat_id: int,
|
||||
photo: bytes,
|
||||
caption: str | None = None,
|
||||
parse_mode: str = "HTML",
|
||||
filename: str = "photo.jpg",
|
||||
content_type: str = "image/jpeg"
|
||||
) -> bool:
|
||||
"""Send a photo to a Telegram chat."""
|
||||
if not self.bot_token:
|
||||
logger.warning("Telegram bot token not configured")
|
||||
return False
|
||||
|
||||
try:
|
||||
timeout = httpx.Timeout(connect=30.0, read=60.0, write=120.0, pool=30.0)
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
data = {"chat_id": str(chat_id)}
|
||||
if caption:
|
||||
data["caption"] = caption
|
||||
data["parse_mode"] = parse_mode
|
||||
|
||||
files = {"photo": (filename, photo, content_type)}
|
||||
|
||||
response = await client.post(
|
||||
f"{self.api_url}/sendPhoto",
|
||||
data=data,
|
||||
files=files,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Failed to send photo to {chat_id}: {response.status_code} - {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending Telegram photo to {chat_id}: {type(e).__name__}: {e}")
|
||||
return False
|
||||
|
||||
async def send_video(
|
||||
self,
|
||||
chat_id: int,
|
||||
video: bytes,
|
||||
caption: str | None = None,
|
||||
parse_mode: str = "HTML",
|
||||
filename: str = "video.mp4",
|
||||
content_type: str = "video/mp4"
|
||||
) -> bool:
|
||||
"""Send a video to a Telegram chat."""
|
||||
if not self.bot_token:
|
||||
logger.warning("Telegram bot token not configured")
|
||||
return False
|
||||
|
||||
try:
|
||||
timeout = httpx.Timeout(connect=30.0, read=120.0, write=300.0, pool=30.0)
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
data = {"chat_id": str(chat_id)}
|
||||
if caption:
|
||||
data["caption"] = caption
|
||||
data["parse_mode"] = parse_mode
|
||||
|
||||
files = {"video": (filename, video, content_type)}
|
||||
|
||||
response = await client.post(
|
||||
f"{self.api_url}/sendVideo",
|
||||
data=data,
|
||||
files=files,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Failed to send video to {chat_id}: {response.status_code} - {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending Telegram video to {chat_id}: {type(e).__name__}: {e}")
|
||||
return False
|
||||
|
||||
async def send_media_group(
|
||||
self,
|
||||
chat_id: int,
|
||||
media_items: list[dict],
|
||||
caption: str | None = None,
|
||||
parse_mode: str = "HTML"
|
||||
) -> bool:
|
||||
"""
|
||||
Send a media group (multiple photos/videos) to a Telegram chat.
|
||||
|
||||
media_items: list of dicts with keys:
|
||||
- type: "photo" or "video"
|
||||
- data: bytes
|
||||
- filename: str
|
||||
- content_type: str
|
||||
"""
|
||||
if not self.bot_token:
|
||||
logger.warning("Telegram bot token not configured")
|
||||
return False
|
||||
|
||||
if not media_items:
|
||||
return False
|
||||
|
||||
try:
|
||||
import json
|
||||
# Use longer timeouts for file uploads
|
||||
timeout = httpx.Timeout(
|
||||
connect=30.0,
|
||||
read=120.0,
|
||||
write=300.0, # 5 minutes for uploading files
|
||||
pool=30.0
|
||||
)
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
# Build media array and files dict
|
||||
media_array = []
|
||||
files_dict = {}
|
||||
|
||||
for i, item in enumerate(media_items):
|
||||
attach_name = f"media{i}"
|
||||
media_obj = {
|
||||
"type": item["type"],
|
||||
"media": f"attach://{attach_name}"
|
||||
}
|
||||
# Only first item gets the caption
|
||||
if i == 0 and caption:
|
||||
media_obj["caption"] = caption
|
||||
media_obj["parse_mode"] = parse_mode
|
||||
|
||||
media_array.append(media_obj)
|
||||
files_dict[attach_name] = (
|
||||
item.get("filename", f"file{i}"),
|
||||
item["data"],
|
||||
item.get("content_type", "application/octet-stream")
|
||||
)
|
||||
|
||||
data = {
|
||||
"chat_id": str(chat_id),
|
||||
"media": json.dumps(media_array)
|
||||
}
|
||||
|
||||
logger.info(f"Sending media group to {chat_id}: {len(media_items)} files")
|
||||
response = await client.post(
|
||||
f"{self.api_url}/sendMediaGroup",
|
||||
data=data,
|
||||
files=files_dict,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
logger.info(f"Successfully sent media group to {chat_id}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Failed to send media group to {chat_id}: {response.status_code} - {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending Telegram media group to {chat_id}: {type(e).__name__}: {e}")
|
||||
return False
|
||||
|
||||
async def send_media_message(
|
||||
self,
|
||||
chat_id: int,
|
||||
text: str | None = None,
|
||||
media_type: str | None = None,
|
||||
media_data: bytes | None = None,
|
||||
media_items: list[dict] | None = None,
|
||||
parse_mode: str = "HTML"
|
||||
) -> bool:
|
||||
"""
|
||||
Send a message with optional media.
|
||||
|
||||
For single media: use media_type and media_data
|
||||
For multiple media: use media_items list with dicts containing:
|
||||
- type: "photo" or "video"
|
||||
- data: bytes
|
||||
- filename: str (optional)
|
||||
- content_type: str (optional)
|
||||
"""
|
||||
# Multiple media - use media group
|
||||
if media_items and len(media_items) > 1:
|
||||
return await self.send_media_group(chat_id, media_items, text, parse_mode)
|
||||
|
||||
# Single media from media_items
|
||||
if media_items and len(media_items) == 1:
|
||||
item = media_items[0]
|
||||
if item["type"] == "photo":
|
||||
return await self.send_photo(
|
||||
chat_id, item["data"], text, parse_mode,
|
||||
item.get("filename", "photo.jpg"),
|
||||
item.get("content_type", "image/jpeg")
|
||||
)
|
||||
elif item["type"] == "video":
|
||||
return await self.send_video(
|
||||
chat_id, item["data"], text, parse_mode,
|
||||
item.get("filename", "video.mp4"),
|
||||
item.get("content_type", "video/mp4")
|
||||
)
|
||||
|
||||
# Legacy single media support
|
||||
if media_data and media_type:
|
||||
if media_type == "photo":
|
||||
return await self.send_photo(chat_id, media_data, text, parse_mode)
|
||||
elif media_type == "video":
|
||||
return await self.send_video(chat_id, media_data, text, parse_mode)
|
||||
|
||||
if text:
|
||||
return await self.send_message(chat_id, text, parse_mode)
|
||||
|
||||
return False
|
||||
|
||||
async def notify_user(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
|
||||
Reference in New Issue
Block a user