Skip to content

Commit

Permalink
Add support for telegram's video stickers
Browse files Browse the repository at this point in the history
  • Loading branch information
akshettrj committed Feb 13, 2023
1 parent 8988123 commit 74cc80b
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 13 deletions.
12 changes: 9 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func main() {
cfg.WhatsApp.LoginDatabase.URL = "file:wawebstore.db?foreign_keys=on"
}

if cfg.GitExecutable == "" || cfg.GoExecutable == "" {
if cfg.GitExecutable == "" || cfg.GoExecutable == "" || cfg.FfmpegExecutable == "" {
gitPath, err := exec.LookPath("git")
if err != nil && !errors.Is(err, exec.ErrDot) {
log.Fatalln("failed to find path to git executable : " + err.Error())
Expand All @@ -62,11 +62,17 @@ func main() {
log.Fatalln("failed to find path to go executable : " + err.Error())
}

ffmpegPath, err := exec.LookPath("ffmpeg")
if err != nil && !errors.Is(err, exec.ErrDot) {
log.Fatalln("failed to find path to ffmpeg executable : " + err.Error())
}

cfg.GitExecutable = gitPath
cfg.GoExecutable = goPath
cfg.FfmpegExecutable = ffmpegPath

log.Printf("Using '%s' and '%s' as path to executables for git and go\n",
gitPath, goPath)
log.Printf("Using '%s', '%s' and '%s' as path to executables for git, go and ffmpeg\n",
gitPath, goPath, ffmpegPath)

cfg.SaveConfig()
}
Expand Down
11 changes: 6 additions & 5 deletions state/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
)

type Config struct {
Path string `yaml:"-"`
TimeZone string `yaml:"time_zone"`
TimeFormat string `yaml:"time_format"`
GitExecutable string `yaml:"git_executable"`
GoExecutable string `yaml:"go_executable"`
Path string `yaml:"-"`
TimeZone string `yaml:"time_zone"`
TimeFormat string `yaml:"time_format"`
GitExecutable string `yaml:"git_executable"`
GoExecutable string `yaml:"go_executable"`
FfmpegExecutable string `yaml:"ffmpeg_executable"`

Telegram struct {
BotToken string `yaml:"bot_token"`
Expand Down
43 changes: 43 additions & 0 deletions utils/stickers.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package utils

import (
"bufio"
"bytes"
"fmt"
"os/exec"

"github.com/Benau/tgsconverter/libtgsconverter"
)
Expand All @@ -27,3 +30,43 @@ func TGSConvertToWebp(tgsStickerData []byte) ([]byte, error) {
}
return nil, fmt.Errorf("sticker has a lot of data which cannot be handled by WhatsApp")
}

func WebmConvertToGif(webmStickerData []byte) ([]byte, error) {

cmd := exec.Command("ffmpeg",
"-f", "webm",
"-i", "-",
"-vf", "scale=w=480:-1:force_original_aspect_ratio=increase",
"-pix_fmt", "rgb24",
"-r", "10",
"-f", "gif",
"-",
)

stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("failed to get ffmpeg's stdin pipe: %s", err)
}

var stdout bytes.Buffer
cmd.Stdout = &stdout

if err = cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start ffmpeg command: %s", err)
}

writer := bufio.NewWriter(stdin)
_, err = writer.Write(webmStickerData)
if err != nil {
return nil, fmt.Errorf("failed to write to stdin: %s", err)
}

writer.Flush()
stdin.Close()

if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("failed waiting for the command to finish: %s", err)
}

return stdout.Bytes(), nil
}
65 changes: 60 additions & 5 deletions utils/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ func TgSendToWhatsApp(b *gotgbot.Bot, c *ext.Context,
Height: proto.Uint32(uint32(msgToForward.Animation.Height)),
Width: proto.Uint32(uint32(msgToForward.Animation.Width)),
Seconds: proto.Uint32(uint32(msgToForward.Animation.Duration)),
GifAttribution: waProto.VideoMessage_GIPHY.Enum(),
GifAttribution: waProto.VideoMessage_TENOR.Enum(),
ContextInfo: &waProto.ContextInfo{},
},
}
Expand Down Expand Up @@ -697,10 +697,10 @@ func TgSendToWhatsApp(b *gotgbot.Bot, c *ext.Context,
return err
}

if msgToForward.Sticker.IsVideo {
_, err := TgReplyTextByContext(b, c, "Unable to send sticker as video stickers are not supported at present", nil)
return err
}
// if msgToForward.Sticker.IsVideo {
// _, err := TgReplyTextByContext(b, c, "Unable to send sticker as video stickers are not supported at present", nil)
// return err
// }

stickerFile, err := b.GetFile(msgToForward.Sticker.FileId, &gotgbot.GetFileOpts{
RequestOpts: &gotgbot.RequestOpts{
Expand All @@ -721,6 +721,61 @@ func TgSendToWhatsApp(b *gotgbot.Bot, c *ext.Context,
if err != nil {
return TgReplyWithErrorByContext(b, c, "Failed to convert TGS sticker to WebP", err)
}
} else if msgToForward.Sticker.IsVideo {
gifBytes, err := WebmConvertToGif(stickerBytes)
if err != nil {
return TgReplyWithErrorByContext(b, c, "Failed to convert WEBM sticker to GIF", err)
}

uploadedAnimation, err := waClient.Upload(context.Background(), gifBytes, whatsmeow.MediaVideo)
if err != nil {
return TgReplyWithErrorByContext(b, c, "Failed to upload animation to WhatsApp", err)
}

msgToSend := &waProto.Message{
VideoMessage: &waProto.VideoMessage{
Url: proto.String(uploadedAnimation.URL),
DirectPath: proto.String(uploadedAnimation.DirectPath),
MediaKey: uploadedAnimation.MediaKey,
Mimetype: proto.String("image/gif"),
GifPlayback: proto.Bool(true),
FileEncSha256: uploadedAnimation.FileEncSHA256,
FileSha256: uploadedAnimation.FileSHA256,
FileLength: proto.Uint64(uint64(len(gifBytes))),
ViewOnce: proto.Bool(msgToForward.HasProtectedContent),
GifAttribution: waProto.VideoMessage_TENOR.Enum(),
ContextInfo: &waProto.ContextInfo{},
},
}
if isReply {
msgToSend.VideoMessage.ContextInfo.StanzaId = proto.String(stanzaId)
msgToSend.VideoMessage.ContextInfo.Participant = proto.String(participant)
msgToSend.VideoMessage.ContextInfo.QuotedMessage = &waProto.Message{Conversation: proto.String("")}
}
if len(mentions) > 0 {
msgToSend.VideoMessage.ContextInfo.MentionedJid = mentions
}

sentMsg, err := waClient.SendMessage(context.Background(), waChatJID, msgToSend)
if err != nil {
return TgReplyWithErrorByContext(b, c, "Failed to send animation to WhatsApp", err)
}
revokeKeyboard := TgMakeRevokeKeyboard(sentMsg.ID, waChatJID.String(), false)
msg, err := TgReplyTextByContext(b, c, "Successfully sent", revokeKeyboard)
if err == nil {
go func(_b *gotgbot.Bot, _m *gotgbot.Message) {
time.Sleep(15 * time.Second)
_b.DeleteMessage(_m.Chat.Id, _m.MessageId, &gotgbot.DeleteMessageOpts{})
}(b, msg)
}

err = database.MsgIdAddNewPair(sentMsg.ID, waClient.Store.ID.User, waChatJID.String(),
cfg.Telegram.TargetChatID, msgToForward.MessageId, msgToForward.MessageThreadId)
if err != nil {
return TgReplyWithErrorByContext(b, c, "Failed to add to database", err)
}

return nil
}

uploadedSticker, err := waClient.Upload(context.Background(), stickerBytes, whatsmeow.MediaImage)
Expand Down

0 comments on commit 74cc80b

Please sign in to comment.