Rebase onto upstream (a4d95fd)
#12
@@ -16,6 +16,10 @@ from nanobot.bus.queue import MessageBus
|
||||
from nanobot.channels.base import BaseChannel
|
||||
from nanobot.config.schema import TelegramConfig
|
||||
|
||||
# Telegram API limits
|
||||
REMOTE_MEDIA_SIZE_LIMIT = 100_000_000 # 100MB for remote URLs
|
||||
TELEGRAM_PHOTO_SIZE_LIMIT = 10_000_000 # 10MB for photos
|
||||
|
||||
|
||||
def _markdown_to_telegram_html(text: str) -> str:
|
||||
"""
|
||||
@@ -250,7 +254,7 @@ class TelegramChannel(BaseChannel):
|
||||
try:
|
||||
# Fetch remote URLs
|
||||
if path.startswith(("http://", "https://")):
|
||||
content, mime = await fetch_media(path, max_bytes=100_000_000)
|
||||
content, mime = await fetch_media(path, max_bytes=REMOTE_MEDIA_SIZE_LIMIT)
|
||||
kind = classify_media(mime)
|
||||
else:
|
||||
# Local file
|
||||
@@ -270,7 +274,13 @@ class TelegramChannel(BaseChannel):
|
||||
try:
|
||||
content = optimize_image(path, max_bytes=6_000_000)
|
||||
except Exception as e:
|
||||
logger.warning(f"Image optimization failed: {e}, sending original")
|
||||
logger.warning(f"Image optimization failed: {e}")
|
||||
# Check if original is under Telegram's limit
|
||||
if len(content) <= TELEGRAM_PHOTO_SIZE_LIMIT:
|
||||
logger.info("Using original image (under 10MB limit)")
|
||||
else:
|
||||
logger.error(f"Original image too large ({len(content)} bytes), skipping")
|
||||
continue
|
||||
|
||||
processed_media.append((path, kind, content))
|
||||
|
||||
@@ -333,12 +343,14 @@ class TelegramChannel(BaseChannel):
|
||||
)
|
||||
|
||||
# Send separate media
|
||||
for i, (path, kind, content) in enumerate(processed_media):
|
||||
first_separate = True
|
||||
for path, kind, content in processed_media:
|
||||
if path in grouping["album"]:
|
||||
continue # Already sent in album
|
||||
|
||||
# Only first separate item gets caption
|
||||
item_caption = media_caption if i == 0 else None
|
||||
item_caption = media_caption if first_separate else None
|
||||
first_separate = False
|
||||
|
||||
if kind == MediaKind.IMAGE:
|
||||
await self._app.bot.send_photo(
|
||||
|
||||
@@ -61,7 +61,6 @@ def detect_mime(path: str, content: bytes | None = None) -> str:
|
||||
return mime
|
||||
except Exception as e:
|
||||
logger.debug(f"Magic detection failed, falling back to extension: {e}")
|
||||
pass # Fall through to extension-based detection
|
||||
|
||||
# Extension-based detection
|
||||
mime_type, _ = mimetypes.guess_type(path)
|
||||
@@ -169,27 +168,26 @@ def optimize_image(path: str, max_bytes: int = TELEGRAM_PHOTO_SIZE_LIMIT) -> byt
|
||||
Raises:
|
||||
ValueError: If image cannot be optimized under limit
|
||||
"""
|
||||
# Load image
|
||||
img = Image.open(path)
|
||||
# Load image with context manager to ensure file handle is closed
|
||||
with Image.open(path) as img:
|
||||
# Convert HEIC to JPEG
|
||||
if is_heic_format(path):
|
||||
if not HAS_HEIF:
|
||||
raise ValueError("pillow-heif not available for HEIC conversion")
|
||||
# Convert to RGB (HEIC → JPEG)
|
||||
if img.mode != "RGB":
|
||||
img = img.convert("RGB")
|
||||
return _optimize_jpeg(img, max_bytes)
|
||||
|
||||
# Convert HEIC to JPEG
|
||||
if is_heic_format(path):
|
||||
if not HAS_HEIF:
|
||||
raise ValueError("pillow-heif not available for HEIC conversion")
|
||||
# Convert to RGB (HEIC → JPEG)
|
||||
# PNG with alpha channel - preserve it
|
||||
if img.mode == "RGBA" or img.mode == "LA":
|
||||
return _optimize_png(img, max_bytes)
|
||||
|
||||
# Everything else → convert to JPEG and optimize
|
||||
if img.mode != "RGB":
|
||||
img = img.convert("RGB")
|
||||
return _optimize_jpeg(img, max_bytes)
|
||||
|
||||
# PNG with alpha channel - preserve it
|
||||
if img.mode == "RGBA" or img.mode == "LA":
|
||||
return _optimize_png(img, max_bytes)
|
||||
|
||||
# Everything else → convert to JPEG and optimize
|
||||
if img.mode != "RGB":
|
||||
img = img.convert("RGB")
|
||||
return _optimize_jpeg(img, max_bytes)
|
||||
|
||||
|
||||
def _optimize_jpeg(img: Image.Image, max_bytes: int) -> bytes:
|
||||
"""Optimize JPEG with size/quality grid."""
|
||||
|
||||
Reference in New Issue
Block a user