Kaynağa Gözat

Merge remote-tracking branch 'origin/sumner/bri-1462-bridge-signal-voice-messages-to-matrix'

Tulir Asokan 3 yıl önce
ebeveyn
işleme
4a7786bf9a
2 değiştirilmiş dosya ile 39 ekleme ve 10 silme
  1. 1 0
      Dockerfile
  2. 38 10
      mautrix_signal/portal.py

+ 1 - 0
Dockerfile

@@ -14,6 +14,7 @@ RUN apk add --no-cache \
       py3-phonenumbers \
       py3-prometheus-client \
       # Other dependencies
+      ffmpeg \
       py3-cryptography \
       py3-protobuf \
       py3-sniffio \

+ 38 - 10
mautrix_signal/portal.py

@@ -68,6 +68,7 @@ from mautrix.types import (
     VideoInfo,
 )
 from mautrix.util.bridge_state import BridgeStateEvent
+from mautrix.util.ffmpeg import convert_bytes, convert_path
 from mautrix.util.format_duration import format_duration
 from mautrix.util.message_send_checkpoint import MessageSendCheckpointStatus
 
@@ -250,11 +251,19 @@ class Portal(DBPortal, BasePortal):
     # region Matrix event handling
 
     @staticmethod
-    def _make_attachment(message: MediaMessageEventContent, path: str) -> Attachment:
+    async def _make_attachment(message: MediaMessageEventContent, path: str) -> Attachment:
+        outgoing_filename = path
+        if message.msgtype == MessageType.AUDIO:
+            outgoing_filename = (
+                (await convert_path(path, ".m4a", output_args=("-c:a", "aac"), remove_input=True))
+                .absolute()
+                .as_posix()
+            )
+            message.info.mimetype = "audio/mp4"
         attachment = Attachment(
             custom_filename=message.body,
             content_type=message.info.mimetype,
-            outgoing_filename=path,
+            outgoing_filename=outgoing_filename,
         )
         info = message.info
         attachment.width = info.get("w", info.get("width", 0))
@@ -345,7 +354,7 @@ class Portal(DBPortal, BasePortal):
             text, mentions = await matrix_to_signal(message)
         elif message.msgtype.is_media:
             attachment_path = await self._download_matrix_media(message)
-            attachment = self._make_attachment(message, attachment_path)
+            attachment = await self._make_attachment(message, attachment_path)
             attachments = [attachment]
             text = message.body if is_relay else None
             self.log.trace("Formed outgoing attachment %s", attachment)
@@ -833,7 +842,9 @@ class Portal(DBPortal, BasePortal):
             self.log.debug(f"Didn't get event ID for {message.timestamp}")
 
     @staticmethod
-    def _make_media_content(attachment: Attachment) -> MediaMessageEventContent:
+    async def _make_media_content(
+        attachment: Attachment, data: bytes
+    ) -> tuple[MediaMessageEventContent, bytes]:
         if attachment.content_type.startswith("image/"):
             msgtype = MessageType.IMAGE
             info = ImageInfo(
@@ -846,7 +857,9 @@ class Portal(DBPortal, BasePortal):
             )
         elif attachment.voice_note or attachment.content_type.startswith("audio/"):
             msgtype = MessageType.AUDIO
-            info = AudioInfo(mimetype=attachment.content_type)
+            info = AudioInfo(
+                mimetype=attachment.content_type if not attachment.voice_note else "audio/ogg"
+            )
         else:
             msgtype = MessageType.FILE
             info = FileInfo(mimetype=attachment.content_type)
@@ -856,10 +869,25 @@ class Portal(DBPortal, BasePortal):
         if attachment.blurhash:
             info["blurhash"] = attachment.blurhash
             info["xyz.amorgan.blurhash"] = attachment.blurhash
-        return MediaMessageEventContent(
+        content = MediaMessageEventContent(
             msgtype=msgtype, info=info, body=attachment.custom_filename
         )
 
+        # If this is a voice note, add the additional voice message metadata and convert to OGG.
+        if attachment.voice_note:
+            content["org.matrix.msc1767.file"] = {
+                "url": content.url,
+                "name": content.body,
+                **(content.file.serialize() if content.file else {}),
+                **(content.info.serialize() if content.info else {}),
+            }
+            content["org.matrix.msc3245.voice"] = {}
+            data = await convert_bytes(
+                data, ".ogg", output_args=("-c:a", "libvorbis"), input_mime=attachment.content_type
+            )
+
+        return content, data
+
     async def _handle_signal_attachment(
         self, intent: IntentAPI, attachment: Attachment, sticker: bool = False
     ) -> MediaMessageEventContent:
@@ -871,15 +899,15 @@ class Portal(DBPortal, BasePortal):
                 else "application/octet-stream"
             )
 
-        content = self._make_media_content(attachment)
-        if sticker:
-            self._adjust_sticker_size(content.info)
-
         with open(attachment.incoming_filename, "rb") as file:
             data = file.read()
         if self.config["signal.remove_file_after_handling"]:
             os.remove(attachment.incoming_filename)
 
+        content, data = await self._make_media_content(attachment, data)
+        if sticker:
+            self._adjust_sticker_size(content.info)
+
         await self._upload_attachment(intent, content, data, attachment.id)
         return content