Rebase onto upstream (a4d95fd) #12

Closed
wylab wants to merge 144 commits from rebase-onto-upstream into main
2 changed files with 31 additions and 21 deletions
Showing only changes of commit 3e6a69d0a8 - Show all commits
+16 -4
View File
@@ -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(
+15 -17
View File
@@ -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."""