import mimetypes import logging from pathlib import Path from yuxi.channel.extensions.tlon.send import send_dm, send_group_message from yuxi.channel.extensions.tlon.story import build_media_story from yuxi.channel.extensions.tlon.send import send_dm_with_story, send_group_message_with_story logger = logging.getLogger(__name__) async def send_text(api, account: dict, target: dict, content: str, reply_to_id: str | None = None) -> str | None: from_ship = account.get("ship", "") if not from_ship: logger.warning("[tlon] No ship configured for outbound send") return None kind = target.get("kind", "dm") if kind == "dm": to_ship = target.get("ship", "") if not to_ship: logger.warning("[tlon] No target ship for DM send") return None return await send_dm(api, from_ship, to_ship, content) elif kind == "group": nest = target.get("nest", "") parts = nest.split("/") if len(parts) < 3: logger.warning("[tlon] Invalid nest format for group send: %s", nest) return None host_ship = parts[1] channel_name = "/".join(parts[2:]) return await send_group_message( api, from_ship, host_ship, channel_name, content, reply_to_id ) return None async def send_media(api, account: dict, target: dict, media_path: str, content_type: str, caption: str | None = None, reply_to_id: str | None = None) -> str | None: from_ship = account.get("ship", "") if not from_ship: logger.warning("[tlon] No ship configured for media send") return None path = Path(media_path) if not path.exists(): logger.warning("[tlon] Media file not found: %s", media_path) caption_text = caption or f"(media: {media_path})" return await send_text(api, account, target, caption_text, reply_to_id) mime_type = content_type or ( mimetypes.guess_type(media_path)[0] or "application/octet-stream" ) media_category = "image" if mime_type.startswith("video/"): media_category = "video" elif mime_type.startswith("audio/"): media_category = "audio" elif not mime_type.startswith("image/"): media_category = "file" try: blob = path.read_bytes() except Exception as e: logger.warning("[tlon] Failed to read media file %s: %s", media_path, e) return await send_text(api, account, target, f"{caption or '(media read error)'}", reply_to_id) try: from yuxi.channel.extensions.tlon.tlon_api import upload_file public_url = await upload_file(api, blob, path.name, mime_type) except Exception as e: logger.warning("[tlon] Upload failed: %s", e) return await send_text(api, account, target, f"{caption or '(media upload failed)'}", reply_to_id) if not public_url: logger.warning("[tlon] Upload returned empty URL, falling back to text") return await send_text(api, account, target, f"{caption or '(media upload failed)'}", reply_to_id) story = build_media_story(caption or "", public_url, media_category) kind = target.get("kind", "dm") if kind == "dm": to_ship = target.get("ship", "") if not to_ship: return None return await send_dm_with_story(api, from_ship, to_ship, story) else: nest = target.get("nest", "") parts = nest.split("/") if len(parts) < 3: return None host_ship = parts[1] channel_name = "/".join(parts[2:]) return await send_group_message_with_story( api, from_ship, host_ship, channel_name, story, reply_to_id )