diff --git a/example-config.yaml b/example-config.yaml
index 5cfed8ea..5d7e4fa8 100644
--- a/example-config.yaml
+++ b/example-config.yaml
@@ -196,20 +196,19 @@ bridge:
# Text msgtypes (m.text, m.notice and m.emote) support HTML, media msgtypes don't.
#
# Available variables:
- # $sender_displayname - The display name of the sender (e.g. Example User)
- # $sender_username - The username (Matrix ID localpart) of the sender (e.g. exampleuser)
- # $sender_mxid - The Matrix ID of the sender (e.g. @exampleuser:example.com)
- # $body - The plaintext body (file name for media msgtypes)
- # $formatted_body - The message content as HTML (for text msgtypes)
+ # $sender_displayname - The display name of the sender (e.g. Example User)
+ # $sender_username - The username (Matrix ID localpart) of the sender (e.g. exampleuser)
+ # $sender_mxid - The Matrix ID of the sender (e.g. @exampleuser:example.com)
+ # $message - The message content
message_formats:
- m.text: "$sender_displayname: $formatted_body"
- m.notice: "$sender_displayname: $formatted_body"
- m.emote: "* $sender_displayname $formatted_body"
- m.file: "$sender_displayname sent a file: $body"
- m.image: "$sender_displayname sent an image: $body"
- m.audio: "$sender_displayname sent an audio file: $body"
- m.video: "$sender_displayname sent a video: $body"
- m.location: "$sender_displayname sent a location: $body"
+ m.text: "$sender_displayname: $message"
+ m.notice: "$sender_displayname: $message"
+ m.emote: "* $sender_displayname $message"
+ m.file: "$sender_displayname sent a file: $message"
+ m.image: "$sender_displayname sent an image: $message"
+ m.audio: "$sender_displayname sent an audio file: $message"
+ m.video: "$sender_displayname sent a video: $message"
+ m.location: "$sender_displayname sent a location: $message"
# Telegram doesn't have built-in emotes, this field specifies how m.emote's from authenticated
# users are sent to telegram. All fields in message_formats are supported. Additionally, the
# Telegram user info is available in the following variables:
diff --git a/mautrix_telegram/commands/handler.py b/mautrix_telegram/commands/handler.py
index f50e59e5..cc728be6 100644
--- a/mautrix_telegram/commands/handler.py
+++ b/mautrix_telegram/commands/handler.py
@@ -18,7 +18,7 @@ from typing import Awaitable, Callable, List, Optional, NamedTuple, Any
from telethon.errors import FloodWaitError
-from mautrix.types import RoomID, EventID
+from mautrix.types import RoomID, EventID, MessageEventContent
from mautrix.bridge.commands import (HelpSection, CommandEvent as BaseCommandEvent,
CommandHandler as BaseCommandHandler,
CommandProcessor as BaseCommandProcessor,
@@ -42,10 +42,10 @@ class CommandEvent(BaseCommandEvent):
sender: u.User
def __init__(self, processor: 'CommandProcessor', room_id: RoomID, event_id: EventID,
- sender: u.User, command: str, args: List[str], is_management: bool,
- is_portal: bool) -> None:
- super().__init__(processor, room_id, event_id, sender, command, args, is_management,
- is_portal)
+ sender: u.User, command: str, args: List[str], content: MessageEventContent,
+ is_management: bool, is_portal: bool) -> None:
+ super().__init__(processor, room_id, event_id, sender, command, args, content,
+ is_management, is_portal)
self.bridge = processor.bridge
self.tgbot = processor.tgbot
self.config = processor.config
@@ -69,7 +69,7 @@ class CommandHandler(BaseCommandHandler):
def __init__(self, handler: Callable[[CommandEvent], Awaitable[EventID]],
management_only: bool, name: str, help_text: str, help_args: str,
help_section: HelpSection, needs_auth: bool, needs_puppeting: bool,
- needs_matrix_puppeting: bool, needs_admin: bool,) -> None:
+ needs_matrix_puppeting: bool, needs_admin: bool) -> None:
super().__init__(handler, management_only, name, help_text, help_args, help_section,
needs_auth=needs_auth, needs_puppeting=needs_puppeting,
needs_matrix_puppeting=needs_matrix_puppeting, needs_admin=needs_admin)
diff --git a/mautrix_telegram/commands/telegram/misc.py b/mautrix_telegram/commands/telegram/misc.py
index f6066ad3..6d9fde77 100644
--- a/mautrix_telegram/commands/telegram/misc.py
+++ b/mautrix_telegram/commands/telegram/misc.py
@@ -29,7 +29,7 @@ from telethon.tl.functions.messages import (ImportChatInviteRequest, CheckChatIn
GetBotCallbackAnswerRequest, SendVoteRequest)
from telethon.tl.functions.channels import JoinChannelRequest
-from mautrix.types import EventID
+from mautrix.types import EventID, Format
from ... import puppet as pu, portal as po
from ...abstract_user import AbstractUser
@@ -45,11 +45,12 @@ async def caption(evt: CommandEvent) -> EventID:
if len(evt.args) == 0:
return await evt.reply("**Usage:** `$cmdprefix+sp caption
`")
- text = " ".join(evt.args)
- evt.sender.command_status = {"caption": text}
- quoted_text = "\n".join(f"> {row}" for row in text.split("\n"))
- return await evt.reply("Your next image will be captioned with\n\n"
- f"{quoted_text}\n\n"
+ prefix = f"{evt.command_prefix} caption "
+ if evt.content.format == Format.HTML:
+ evt.content.formatted_body = evt.content.formatted_body.replace(prefix, "", 1)
+ evt.content.body = evt.content.body.replace(prefix, "", 1)
+ evt.sender.command_status = {"caption": evt.content}
+ return await evt.reply("Your next image or file will be sent with that caption. "
"Use `$cmdprefix+sp cancel` to cancel the caption.")
diff --git a/mautrix_telegram/portal/matrix.py b/mautrix_telegram/portal/matrix.py
index f59d2222..95c509e6 100644
--- a/mautrix_telegram/portal/matrix.py
+++ b/mautrix_telegram/portal/matrix.py
@@ -169,7 +169,7 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
async def _apply_msg_format(self, sender: 'u.User', content: MessageEventContent
) -> None:
- if isinstance(content, TextMessageEventContent) and content.format != Format.HTML:
+ if not isinstance(content, TextMessageEventContent) or content.format != Format.HTML:
content.format = Format.HTML
content.formatted_body = escape_html(content.body).replace("\n", "
")
@@ -179,14 +179,9 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
tpl_args = dict(sender_mxid=sender.mxid,
sender_username=sender.mxid_localpart,
sender_displayname=escape_html(displayname),
- body=content.body)
- if isinstance(content, TextMessageEventContent):
- tpl_args["formatted_body"] = content.formatted_body
- tpl_args["message"] = content.formatted_body
- content.formatted_body = Template(tpl).safe_substitute(tpl_args)
- else:
- tpl_args["message"] = content.body
- content.body = Template(tpl).safe_substitute(tpl_args)
+ message=content.formatted_body,
+ body=content.body, formatted_body=content.formatted_body)
+ content.formatted_body = Template(tpl).safe_substitute(tpl_args)
async def _apply_emote_format(self, sender: 'u.User',
content: TextMessageEventContent) -> None:
@@ -248,7 +243,8 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
async def _handle_matrix_file(self, sender_id: TelegramID, event_id: EventID,
space: TelegramID, client: 'MautrixTelegramClient',
- content: MediaMessageEventContent, reply_to: TelegramID) -> None:
+ content: MediaMessageEventContent, reply_to: TelegramID,
+ caption: TextMessageEventContent = None) -> None:
mime = content.info.mimetype
w, h = content.info.width, content.info.height
file_name = content["net.maunium.telegram.internal.filename"]
@@ -256,7 +252,7 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
if config["bridge.parallel_file_transfer"]:
file_handle, file_size = await parallel_transfer_to_telegram(client, self.main_intent,
- content.url, 0)
+ content.url, sender_id)
else:
file = await self.main_intent.download_media(content.url)
@@ -283,19 +279,19 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
media = InputMediaUploadedDocument(file=file_handle, attributes=attributes,
mime_type=mime or "application/octet-stream")
- caption = content.body if content.body != file_name else None
+ caption, entities = self._matrix_event_to_entities(caption) if caption else (None, None)
async with self.send_lock(sender_id):
if await self._matrix_document_edit(client, content, space, caption, media, event_id):
return
try:
response = await client.send_media(self.peer, media, reply_to=reply_to,
- caption=caption)
+ caption=caption, entities=entities)
except (PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, PhotoExtInvalidError):
media = InputMediaUploadedDocument(file=media.file, mime_type=mime,
attributes=attributes)
response = await client.send_media(self.peer, media, reply_to=reply_to,
- caption=caption)
+ caption=caption, entities=entities)
self._add_telegram_message_to_db(event_id, space, 0, response)
async def _matrix_document_edit(self, client: 'MautrixTelegramClient',
@@ -364,14 +360,18 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
media = (MessageType.STICKER, MessageType.IMAGE, MessageType.FILE, MessageType.AUDIO,
MessageType.VIDEO)
+ caption_content = None
if content.msgtype in media:
content["net.maunium.telegram.internal.filename"] = content.body
try:
- content.body = sender.command_status["caption"]
+ caption_content: MessageEventContent = sender.command_status["caption"]
+ caption_content.msgtype = content.msgtype
+ reply_to = reply_to or formatter.matrix_reply_to_telegram(caption_content, space,
+ room_id=self.mxid)
sender.command_status = None
except (KeyError, TypeError):
pass
- await self._pre_process_matrix_message(sender, not logged_in, content)
+ await self._pre_process_matrix_message(sender, not logged_in, caption_content or content)
if content.msgtype == MessageType.NOTICE:
bridge_notices = self.get_config("bridge_notices.default")
@@ -385,7 +385,8 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC):
await self._handle_matrix_location(sender_id, event_id, space, client, content,
reply_to)
elif content.msgtype in media:
- await self._handle_matrix_file(sender_id, event_id, space, client, content, reply_to)
+ await self._handle_matrix_file(sender_id, event_id, space, client, content, reply_to,
+ caption_content)
else:
self.log.debug(f"Unhandled Matrix event: {content}")