diff --git a/mautrix_facebook/config.py b/mautrix_facebook/config.py
index 818f1d94..13f7dd95 100644
--- a/mautrix_facebook/config.py
+++ b/mautrix_facebook/config.py
@@ -143,6 +143,8 @@ def do_update(self, helper: ConfigUpdateHelper) -> None:
if isinstance(value, list) and len(value) != 2:
raise ValueError(f"{key} must only be a list of two items")
+ copy("bridge.convert_animated_webp_attachments")
+
copy("facebook.device_seed")
if base["facebook.device_seed"] == "generate":
base["facebook.device_seed"] = self._new_token()
diff --git a/mautrix_facebook/example-config.yaml b/mautrix_facebook/example-config.yaml
index 1f37eee6..6906b620 100644
--- a/mautrix_facebook/example-config.yaml
+++ b/mautrix_facebook/example-config.yaml
@@ -367,6 +367,10 @@ bridge:
m.video: '$sender_displayname sent a video'
m.location: '$sender_displayname sent a location'
+ # Whether to convert animated webp to gifs. Element for Android does not support
+ # Animated WebP (https://github.com/vector-im/element-android/issues/2695).
+ convert_animated_webp_attachments: false
+
facebook:
device_seed: generate
default_region_hint: ODN
diff --git a/mautrix_facebook/portal.py b/mautrix_facebook/portal.py
index 3798d6fb..9113a29a 100644
--- a/mautrix_facebook/portal.py
+++ b/mautrix_facebook/portal.py
@@ -340,6 +340,7 @@ async def _reupload_fb_file(
referer: str = "messenger_thread_photo",
find_size: bool = False,
convert_audio: bool = False,
+ convert_animated_webp_to_gif: bool = False,
) -> tuple[ContentURI, FileInfo | VideoInfo | AudioInfo | ImageInfo, EncryptedFile | None]:
if not url:
raise ValueError("URL not provided")
@@ -357,6 +358,22 @@ async def _reupload_fb_file(
data, ".ogg", output_args=("-c:a", "libopus"), input_mime=mime
)
mime = "audio/ogg"
+ if convert_animated_webp_to_gif and mime == "image/webp":
+ with Image.open(BytesIO(data)) as img:
+ with BytesIO() as data_bytes:
+ loop = img.info.get("loop", 0)
+ duration = img.info.get("duration", 70)
+ img.save(
+ data_bytes,
+ "gif",
+ save_all=True,
+ duration=duration,
+ loop=loop,
+ background=0,
+ )
+ data = data_bytes.getvalue()
+ mime = "image/gif"
+
info = FileInfo(mimetype=mime, size=len(data))
if Image and mime.startswith("image/") and find_size:
with Image.open(BytesIO(data)) as img:
@@ -1936,6 +1953,7 @@ async def _convert_mqtt_attachment(
return TextMessageEventContent(
msgtype=MessageType.NOTICE, body="Unsupported attachment"
)
+ convert_animated_webp_to_gif = self.config["bridge.convert_animated_webp_attachments"]
mxc, additional_info, decryption_info = await self._reupload_fb_file(
url,
source,
@@ -1945,9 +1963,10 @@ async def _convert_mqtt_attachment(
find_size=False,
referer=referer,
convert_audio=voice_message,
+ convert_animated_webp_to_gif=convert_animated_webp_to_gif,
)
info.size = additional_info.size
- info.mimetype = attachment.mime_type or additional_info.mimetype
+ info.mimetype = additional_info.mimetype or attachment.mime_type
content = MediaMessageEventContent(
url=mxc, file=decryption_info, msgtype=msgtype, body=filename, info=info
)