Add support for converting video stickers to images
This commit is contained in:
+4
-1
@@ -6,7 +6,7 @@ Minimum Conduit version remains at 0.4.0.
|
||||
|
||||
### Added
|
||||
* Added provisioning API for resolving Telegram identifiers (like usernames).
|
||||
* Added basic bridging of Telegram custom emojis to Matrix.
|
||||
* Added support for bridging Telegram custom emojis to Matrix.
|
||||
* Added option to not bridge chats with lots of members.
|
||||
* Added option to include captions in the same message as the media to
|
||||
implement [MSC2530]. Sending captions the same way is also supported and
|
||||
@@ -33,6 +33,9 @@ Minimum Conduit version remains at 0.4.0.
|
||||
### Improved
|
||||
* Improved handling the bridge user leaving chats on Telegram, and new users
|
||||
being added on Telegram.
|
||||
* Improved animated sticker conversion options: added support for animated webp
|
||||
and added option to convert video stickers (webm) to the specified image
|
||||
format.
|
||||
* Audio and video metadata is now bridged properly to Telegram.
|
||||
* Added database index on Telegram usernames (used when bridging username
|
||||
@-mentions in messages).
|
||||
|
||||
@@ -145,9 +145,14 @@ class Config(BaseBridgeConfig):
|
||||
copy("bridge.parallel_file_transfer")
|
||||
copy("bridge.federate_rooms")
|
||||
copy("bridge.animated_sticker.target")
|
||||
copy("bridge.animated_sticker.convert_from_webm")
|
||||
copy("bridge.animated_sticker.args.width")
|
||||
copy("bridge.animated_sticker.args.height")
|
||||
copy("bridge.animated_sticker.args.fps")
|
||||
copy("bridge.animated_emoji.target")
|
||||
copy("bridge.animated_emoji.args.width")
|
||||
copy("bridge.animated_emoji.args.height")
|
||||
copy("bridge.animated_emoji.args.fps")
|
||||
copy("bridge.private_chat_portal_meta")
|
||||
copy("bridge.delivery_receipts")
|
||||
copy("bridge.delivery_error_reports")
|
||||
|
||||
@@ -230,11 +230,22 @@ bridge:
|
||||
# webm - converts to webm video, requires ffmpeg executable with vp9 codec and webm container support
|
||||
# webp - converts to animated webp, requires ffmpeg executable with webp codec/container support
|
||||
target: gif
|
||||
# Should video stickers be converted to the specified format as well?
|
||||
convert_from_webm: false
|
||||
# Arguments for converter. All converters take width and height.
|
||||
args:
|
||||
width: 256
|
||||
height: 256
|
||||
fps: 25 # only for webm, webp and gif (2, 5, 10, 20 or 25 recommended)
|
||||
# Settings for converting animated emoji.
|
||||
# Same as animated_sticker, but webm is not supported as the target
|
||||
# (because inline images can only contain images, not videos).
|
||||
animated_emoji:
|
||||
target: webp
|
||||
args:
|
||||
width: 64
|
||||
height: 64
|
||||
fps: 25
|
||||
# End-to-bridge encryption support options.
|
||||
#
|
||||
# See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info.
|
||||
|
||||
@@ -413,13 +413,15 @@ class TelegramMessageConverter:
|
||||
thumb_loc = None
|
||||
thumb_size = None
|
||||
parallel_id = source.tgid if self.config["bridge.parallel_file_transfer"] else None
|
||||
tgs_convert = self.config["bridge.animated_sticker"]
|
||||
file = await util.transfer_file_to_matrix(
|
||||
source.client,
|
||||
intent,
|
||||
document,
|
||||
thumb_loc,
|
||||
is_sticker=attrs.is_sticker,
|
||||
tgs_convert=self.config["bridge.animated_sticker"],
|
||||
tgs_convert=tgs_convert,
|
||||
webm_convert=tgs_convert["target"] if tgs_convert["convert_from_webm"] else None,
|
||||
filename=attrs.name,
|
||||
parallel_id=parallel_id,
|
||||
encrypt=self.portal.encrypted,
|
||||
|
||||
@@ -52,6 +52,7 @@ from ..tgclient import MautrixTelegramClient
|
||||
from ..util import sane_mimetypes
|
||||
from .parallel_file_transfer import parallel_transfer_to_matrix
|
||||
from .tgs_converter import convert_tgs_to
|
||||
from .webm_converter import convert_webm_to
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
@@ -228,10 +229,8 @@ async def transfer_custom_emojis_to_matrix(
|
||||
GetCustomEmojiDocumentsRequest(document_id=not_existing_ids)
|
||||
)
|
||||
|
||||
tgs_args = source.config["bridge.animated_sticker"]
|
||||
if tgs_args["target"] == "webm":
|
||||
# Inline images can't be videos, let's hope animated webp is supported
|
||||
tgs_args = {**tgs_args, "target": "webp"}
|
||||
tgs_args = source.config["bridge.animated_emoji"]
|
||||
webm_convert = tgs_args["target"]
|
||||
|
||||
transfer_sema = asyncio.Semaphore(5)
|
||||
|
||||
@@ -243,6 +242,7 @@ async def transfer_custom_emojis_to_matrix(
|
||||
document,
|
||||
is_sticker=True,
|
||||
tgs_convert=tgs_args,
|
||||
webm_convert=webm_convert,
|
||||
filename=f"emoji-{document.id}",
|
||||
# Emojis are used as inline images and can't be encrypted
|
||||
encrypt=False,
|
||||
@@ -261,6 +261,7 @@ async def transfer_file_to_matrix(
|
||||
*,
|
||||
is_sticker: bool = False,
|
||||
tgs_convert: dict | None = None,
|
||||
webm_convert: str | None = None,
|
||||
filename: str | None = None,
|
||||
encrypt: bool = False,
|
||||
parallel_id: int | None = None,
|
||||
@@ -290,6 +291,7 @@ async def transfer_file_to_matrix(
|
||||
thumbnail,
|
||||
is_sticker,
|
||||
tgs_convert,
|
||||
webm_convert,
|
||||
filename,
|
||||
encrypt,
|
||||
parallel_id,
|
||||
@@ -305,6 +307,7 @@ async def _unlocked_transfer_file_to_matrix(
|
||||
thumbnail: TypeThumbnail,
|
||||
is_sticker: bool,
|
||||
tgs_convert: dict | None,
|
||||
webm_convert: str | None,
|
||||
filename: str | None,
|
||||
encrypt: bool,
|
||||
parallel_id: int | None,
|
||||
@@ -348,6 +351,12 @@ async def _unlocked_transfer_file_to_matrix(
|
||||
width, height = converted_anim.width, converted_anim.height
|
||||
image_converted = mime_type != "application/gzip"
|
||||
thumbnail = None
|
||||
elif is_sticker and webm_convert and webm_convert != "webm" and mime_type == "video/webm":
|
||||
converted_anim = await convert_webm_to(file, webm_convert)
|
||||
mime_type = converted_anim.mime
|
||||
file = converted_anim.data
|
||||
image_converted = mime_type != "video/webm"
|
||||
thumbnail = None
|
||||
|
||||
decryption_info = None
|
||||
upload_mime_type = mime_type
|
||||
|
||||
@@ -99,7 +99,7 @@ if lottieconverter:
|
||||
converters["png"] = tgs_to_png
|
||||
converters["gif"] = tgs_to_gif
|
||||
|
||||
if lottieconverter and ffmpeg:
|
||||
if lottieconverter and ffmpeg.ffmpeg_path:
|
||||
|
||||
async def tgs_to_webm(
|
||||
file: bytes, width: int, height: int, fps: int = 30, **_: Any
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# mautrix-telegram - A Matrix-Telegram puppeting bridge
|
||||
# Copyright (C) 2022 Tulir Asokan
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from mautrix.util import ffmpeg
|
||||
|
||||
from .tgs_converter import ConvertedSticker
|
||||
|
||||
log: logging.Logger = logging.getLogger("mau.util.webm")
|
||||
|
||||
|
||||
converter_args = {
|
||||
"gif": {
|
||||
"output_args": ("-vf", "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse"),
|
||||
},
|
||||
"png": {
|
||||
"input_args": ("-ss", "0"),
|
||||
"output_args": ("-frames:v", "1"),
|
||||
},
|
||||
"webp": {},
|
||||
}
|
||||
|
||||
|
||||
async def convert_webm_to(file: bytes, convert_to: str) -> ConvertedSticker:
|
||||
if convert_to in ("png", "gif", "webp"):
|
||||
try:
|
||||
converted_data = await ffmpeg.convert_bytes(
|
||||
data=file,
|
||||
output_extension=f".{convert_to}",
|
||||
**converter_args[convert_to],
|
||||
)
|
||||
return ConvertedSticker(f"image/{convert_to}", converted_data)
|
||||
except ffmpeg.ConverterError as e:
|
||||
log.error(str(e))
|
||||
elif convert_to != "disable":
|
||||
log.warning(f"Unable to convert webm animated sticker, type {convert_to} not supported")
|
||||
return ConvertedSticker("video/webm", file)
|
||||
Reference in New Issue
Block a user