소스 검색

link previews: support from Beeper -> Signal

Sumner Evans 3 년 전
부모
커밋
95f101da25
2개의 변경된 파일38개의 추가작업 그리고 0개의 파일을 삭제
  1. 4 0
      mausignald/signald.py
  2. 34 0
      mautrix_signal/portal.py

+ 4 - 0
mausignald/signald.py

@@ -24,6 +24,7 @@ from .types import (
     GroupID,
     GroupV2,
     IncomingMessage,
+    LinkPreview,
     LinkSession,
     Mention,
     Profile,
@@ -212,12 +213,14 @@ class SignaldClient(SignaldRPCClient):
         quote: Quote | None = None,
         attachments: list[Attachment] | None = None,
         mentions: list[Mention] | None = None,
+        previews: list[LinkPreview] | None = None,
         timestamp: int | None = None,
         req_id: UUID | None = None,
     ) -> None:
         serialized_quote = quote.serialize() if quote else None
         serialized_attachments = [attachment.serialize() for attachment in (attachments or [])]
         serialized_mentions = [mention.serialize() for mention in (mentions or [])]
+        serialized_previews = [preview.serialize() for preview in (previews or [])]
         resp = await self.request_v1(
             "send",
             username=username,
@@ -225,6 +228,7 @@ class SignaldClient(SignaldRPCClient):
             attachments=serialized_attachments,
             quote=serialized_quote,
             mentions=serialized_mentions,
+            previews=serialized_previews,
             timestamp=timestamp,
             req_id=req_id,
             **self._recipient_to_args(recipient),

+ 34 - 0
mautrix_signal/portal.py

@@ -55,6 +55,7 @@ from mautrix.types import (
     AudioInfo,
     ContentURI,
     EncryptedEvent,
+    EncryptedFile,
     EventID,
     EventType,
     FileInfo,
@@ -318,6 +319,32 @@ class Portal(DBPortal, BasePortal):
                 ),
             )
 
+    async def _beeper_link_preview_to_signal(
+        self, beeper_link_preview: dict[str, Any]
+    ) -> LinkPreview | None:
+        link_preview = LinkPreview(
+            url=beeper_link_preview["matched_url"],
+            title=beeper_link_preview.get("og:title", ""),
+            description=beeper_link_preview.get("og:description", ""),
+        )
+        if BEEPER_IMAGE_ENCRYPTION_KEY in beeper_link_preview or "og:image" in beeper_link_preview:
+            if BEEPER_IMAGE_ENCRYPTION_KEY in beeper_link_preview:
+                file = EncryptedFile.deserialize(beeper_link_preview[BEEPER_IMAGE_ENCRYPTION_KEY])
+                data = await self.main_intent.download_media(file.url)
+                data = decrypt_attachment(data, file.key.key, file.hashes.get("sha256"), file.iv)
+            else:
+                data = await self.main_intent.download_media(beeper_link_preview["og:image"])
+
+            attachment_path = self._write_outgoing_file(data)
+            link_preview.attachment = Attachment(
+                content_type=beeper_link_preview.get("og:image:type"),
+                outgoing_filename=attachment_path,
+                width=beeper_link_preview.get("og:image:width", 0),
+                height=beeper_link_preview.get("og:image:height", 0),
+                size=beeper_link_preview.get("matrix:image:size", 0),
+            )
+        return link_preview
+
     async def _handle_matrix_message(
         self, sender: u.User, message: MessageEventContent, event_id: EventID
     ) -> None:
@@ -352,8 +379,14 @@ class Portal(DBPortal, BasePortal):
         attachments: list[Attachment] | None = None
         attachment_path: str | None = None
         mentions: list[Mention] | None = None
+        link_previews: list[LinkPreview] | None = None
         if message.msgtype.is_text:
             text, mentions = await matrix_to_signal(message)
+            message_previews = message.get(BEEPER_LINK_PREVIEWS_KEY, [])
+            potential_link_previews = await asyncio.gather(
+                *(self._beeper_link_preview_to_signal(m) for m in message_previews)
+            )
+            link_previews = [p for p in potential_link_previews if p is not None]
         elif message.msgtype.is_media:
             attachment_path = await self._download_matrix_media(message)
             attachment = await self._make_attachment(message, attachment_path)
@@ -376,6 +409,7 @@ class Portal(DBPortal, BasePortal):
                 recipient=self.chat_id,
                 body=text,
                 mentions=mentions,
+                previews=link_previews,
                 quote=quote,
                 attachments=attachments,
                 timestamp=request_id,