diff --git a/ntfy/bot.py b/ntfy/bot.py index 918b9ab..297fee1 100644 --- a/ntfy/bot.py +++ b/ntfy/bot.py @@ -1,13 +1,14 @@ import asyncio from html import escape import json -from typing import Any, Dict, Tuple, List, Awaitable, Callable +from typing import Any, Dict, Tuple, List, Awaitable, Callable, NamedTuple from aiohttp import ClientTimeout from maubot import MessageEvent, Plugin from maubot.handlers import command from mautrix.types import (EventType, Format, MessageType, - TextMessageEventContent, RoomID, EventID) + TextMessageEventContent, RoomID, EventID, + MediaMessageEventContent, ImageInfo, ContentURI) from mautrix.util.async_db import UpgradeTable from mautrix.util.config import BaseProxyConfig from mautrix.util.formatter import parse_html @@ -18,6 +19,13 @@ from .emoji import (EMOJI_FALLBACK, WHITE_CHECK_MARK, REPEAT, NO_ENTRY, WARNING, parse_tags) from .exceptions import SubscriptionError +Media = NamedTuple("Media", [ + ("name", str), + ("mime_type", str), + ("url", str), + ("size", int), +]) + async def build_notice(html_content) -> TextMessageEventContent: """ @@ -53,6 +61,18 @@ def ensure_permission(func: Callable): return wrapper +def extract_media(message) -> Media | None: + media = message.get("attachment", None) + + if media: + return Media(name=media.get("name", None), + mime_type=media.get("type", None), + url=media.get("url", None), + size=media.get("size", None)) + + return + + class NtfyBot(Plugin): db: DB config: Config @@ -491,6 +511,8 @@ class NtfyBot(Plugin): # Build matrix message html_content = self.build_message_content( topic.server, message) + media = extract_media(message) + media_content = None text_content = await parse_html(html_content.strip()) content = TextMessageEventContent( msgtype=MessageType.NOTICE, @@ -498,15 +520,39 @@ class NtfyBot(Plugin): formatted_body=html_content, body=text_content, ) + if media and media.mime_type in ["image/jpeg", "image/png"]: + media_content = MediaMessageEventContent( + msgtype=MessageType.IMAGE, + url=ContentURI(media.url), + body=media.name, + info=ImageInfo( + mimetype=media.mime_type, + size=media.size, + ), + ) + elif media: + media_content = MediaMessageEventContent( + msgtype=MessageType.FILE, + url=ContentURI(media.url), + body=media.name, + info=ImageInfo( + mimetype=media.mime_type, + size=media.size, + ), + ) # Broadcast the message to all subscribed rooms subscriptions = await self.db.get_subscriptions_by_topic_id( topic.id) room_ids = [sub.room_id for sub in subscriptions] await self.broadcast_to_rooms(room_ids, content) + if media_content: + await self.broadcast_to_rooms(room_ids, media_content) - async def broadcast_to_rooms(self, room_ids: List[RoomID], - content: TextMessageEventContent): + async def broadcast_to_rooms(self, + room_ids: List[RoomID], + content: (TextMessageEventContent | + MediaMessageEventContent)) -> None: """ Broadcast a message to multiple rooms concurrently. :param room_ids: @@ -614,7 +660,6 @@ class NtfyBot(Plugin): title = message.get("title", None) tags = message.get("tags", None) click = message.get("click", None) - attachment = message.get("attachment", None) if tags: (emoji, non_emoji) = parse_tags(self.log, tags) @@ -648,12 +693,6 @@ class NtfyBot(Plugin): html_content += "
Tags: %s" % escape( tags) - # build attachment - if attachment: - html_content += "
View %s" % (escape( - attachment["url"]), escape(attachment["name"])) - html_content += "" - return html_content @classmethod