Skip to content

Commit

Permalink
add video sticker
Browse files Browse the repository at this point in the history
  • Loading branch information
armpico committed Apr 22, 2022
1 parent 0ab1c0b commit 4c77096
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 13 deletions.
44 changes: 44 additions & 0 deletions picobot/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
from .config import CREATOR_ID, ROOT_DIR
from .msg_type import MsgType
from .painter import sticker_from_image, sticker_from_text
from .video_editor import sticker_from_video
from .repository.repo import repository

IMG_DIR = ROOT_DIR / 'images'
VID_DIR = ROOT_DIR / 'videos'
IMG_PREFIX = 'img'
VIDEO_PREFIX = 'vid'
AVATAR_PREFIX = 'avatar'

logging.basicConfig(
Expand Down Expand Up @@ -159,6 +161,12 @@ def add_sticker(update: Update, context: CallbackContext):
elif msg_type == MsgType.REP_PHOTO:
if add_photo(bot, msg, user_id, pack_name, emoji, True):
return
elif msg_type == MsgType.VIDEO:
if add_video(bot, msg, user_id, pack_name, emoji, False):
return
elif msg_type == MsgType.REP_VIDEO:
if add_video(bot, msg, user_id, pack_name, emoji, True):
return
elif msg_type == MsgType.DOCUMENT:
if add_document(bot, msg, user_id, pack_name, emoji, False):
return
Expand Down Expand Up @@ -264,6 +272,40 @@ def add_photo(bot: Bot, msg: Message, user_id: int, pack_name: str, emoji: str,
return True


def add_video(bot: Bot, msg: Message, user_id: int, pack_name: str, emoji: str, replied: bool):
if replied:
msg.reply_to_message
video = msg.reply_to_message.video
else:
video = msg.video[-1]
video_path = VID_DIR / f'{VIDEO_PREFIX}{user_id}.mp4'
try:
if bot.get_file(video.file_id).file_size > 2172859:
raise Exception("File size exceeds limits")
bot.get_file(video.file_id).download(custom_path=video_path)
# resize and save as webm
video_path = sticker_from_video(video_path)
with open(video_path, 'rb') as webm_sticker:
bot.add_sticker_to_set(
user_id=user_id, name=pack_name, webm_sticker=webm_sticker, emojis=emoji
)
sticker = bot.get_sticker_set(pack_name).stickers[-1]
msg.reply_sticker(sticker)
except Exception as exc:
if isinstance(exc, telegram.error.BadRequest):
exception_msg = exc.message.lower()
if exception_msg in responses.TELEGRAM_ERROR_CODES:
msg.reply_text(responses.TELEGRAM_ERROR_CODES[exception_msg])
return True
logger.error(
"Exception on add_video. User id %d Pack %s", user_id, pack_name,
)
logger.error(exc)
return False

return True


def add_document(bot: Bot, msg: Message, user_id: int, pack_name: str, emoji: str, replied: bool):
if replied:
doc = msg.reply_to_message.document
Expand Down Expand Up @@ -428,6 +470,8 @@ def get_msg_type(message: Message):

if message.photo is not None and len(message.photo) > 0:
msg_type = MsgType.PHOTO
elif message.video is not None:
msg_type = MsgType.VIDEO
elif message.sticker is not None:
msg_type = MsgType.STICKER
elif message.document is not None:
Expand Down
2 changes: 2 additions & 0 deletions picobot/msg_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ class MsgType(IntEnum):
PHOTO = 2
DOCUMENT = 3
STICKER = 4
VIDEO = 5
REP_TEXT = 10
REP_PHOTO = 20
REP_DOCUMENT = 30
REP_STICKER = 40
REP_VIDEO = 50
42 changes: 42 additions & 0 deletions picobot/video_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pathlib import Path
import ffmpeg


def sticker_from_video(mp4_path: Path):
'''
Converts the given video to a proper format that can be uploaded as a sticker.
Telegram accepts WEBM VP9 with a maximum size of 512x512 pixels with maximum 3 seconds duration.
'''
probe = ffmpeg.probe(mp4_path)
video_stream = next(
(stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None
)
width = int(video_stream['width'])
height = int(video_stream['height'])
duration = float(probe['format']['duration'])

if duration > 3.0:
raise ValueError('Video duration exceeds limits')

(width, height) = estimate_video_sticker_size(width, height)
vid_output_path = mp4_path.with_suffix('.webm')
(
ffmpeg.input(mp4_path)
.video.filter('scale', width, height)
.output(filename=vid_output_path.as_posix(), format='webm', vcodec='libvpx-vp9')
.run(overwrite_output=True)
)
return vid_output_path


def estimate_video_sticker_size(width: int, height: int) -> tuple[int, int]:
'''
Estimates the frame size to fit Telegram restrictions (maximum size of 512x512 pixels), keeping its aspect ratio.
'''
if width >= height:
ratio = 512 / width
return (512, int(ratio * height))
else:
ratio = 512 / height
return (int(ratio * width), 512)

42 changes: 30 additions & 12 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pillow = "^8.0"
python-slugify = "^4.0"
emoji = "^0.6.0"
typed-ast = "^1.5.2"
PythonVideoConverter = "^1.0.3"
ffmpeg-python = "^0.2.0"

[tool.poetry.dev-dependencies]
pytest = "^3.0"
Expand Down

0 comments on commit 4c77096

Please sign in to comment.