From ace21c68cd3db168d619d8d469105aaab599fb12 Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Wed, 11 Oct 2023 10:28:46 +0700 Subject: [PATCH] feat: update package & add reaction ID & image caption (#94) feat: update package & add feature --- LICENCE.txt | 21 +++++++ src/go.mod | 4 +- src/go.sum | 14 ++--- src/pkg/whatsapp/whatsapp.go | 106 +++++++++++++++++++++-------------- 4 files changed, 90 insertions(+), 55 deletions(-) create mode 100644 LICENCE.txt diff --git a/LICENCE.txt b/LICENCE.txt new file mode 100644 index 0000000..34fbff4 --- /dev/null +++ b/LICENCE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Aldino Kemal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/go.mod b/src/go.mod index d492b6b..d651912 100644 --- a/src/go.mod +++ b/src/go.mod @@ -9,7 +9,7 @@ require ( github.com/gofiber/fiber/v2 v2.48.0 github.com/gofiber/template/html/v2 v2.0.5 github.com/gofiber/websocket/v2 v2.2.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/h2non/bimg v1.1.9 github.com/markbates/pkger v0.17.1 github.com/mattn/go-sqlite3 v1.14.17 @@ -19,7 +19,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/valyala/fasthttp v1.48.0 go.mau.fi/libsignal v0.1.0 - go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1 + go.mau.fi/whatsmeow v0.0.0-20231006094259-c6eaf52f1357 google.golang.org/protobuf v1.31.0 ) diff --git a/src/go.sum b/src/go.sum index d28effb..2d93606 100644 --- a/src/go.sum +++ b/src/go.sum @@ -35,8 +35,8 @@ github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7P github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/h2non/bimg v1.1.9 h1:WH20Nxko9l/HFm4kZCA3Phbgu2cbHvYzxwxn9YROEGg= @@ -96,14 +96,10 @@ go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c= go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I= go.mau.fi/util v0.1.0 h1:BwIFWIOEeO7lsiI2eWKFkWTfc5yQmoe+0FYyOFVyaoE= go.mau.fi/util v0.1.0/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84= -go.mau.fi/whatsmeow v0.0.0-20230718190209-efef6f1cec8e h1:i2atPgn2MRLGxisk+EZM1b1RfPh+4dZxSc8OdyvzutY= -go.mau.fi/whatsmeow v0.0.0-20230718190209-efef6f1cec8e/go.mod h1:+ObGpFE6cbbY4hKc1FmQH9MVfqaemmlXGXSnwDvCOyE= -go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1 h1:tfVqib0PAAgMJrZu/Ko25J436e91HKgZepwdhgPmeHM= -go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1/go.mod h1:1xFS2b5zqsg53ApsYB4FDtko7xG7r+gVgBjh9k+9/GE= +go.mau.fi/whatsmeow v0.0.0-20231006094259-c6eaf52f1357 h1:/le5a7Gzr9MhiZghMs/Aq3az0vyknJSqWUKdQvRaAIg= +go.mau.fi/whatsmeow v0.0.0-20231006094259-c6eaf52f1357/go.mod h1:1xFS2b5zqsg53ApsYB4FDtko7xG7r+gVgBjh9k+9/GE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -126,8 +122,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/src/pkg/whatsapp/whatsapp.go b/src/pkg/whatsapp/whatsapp.go index b61ddf5..cd52dca 100644 --- a/src/pkg/whatsapp/whatsapp.go +++ b/src/pkg/whatsapp/whatsapp.go @@ -35,6 +35,22 @@ var ( startupTime = time.Now().Unix() ) +type ExtractedMedia struct { + MediaPath string `json:"media_path"` + MimeType string `json:"mime_type"` + Caption string `json:"caption"` +} + +type evtReaction struct { + ID string `json:"id"` + Message string `json:"message"` +} + +type evtMessage struct { + ID string `json:"id"` + Text string `json:"text"` +} + func SanitizePhone(phone *string) { if phone != nil && len(*phone) > 0 && !strings.Contains(*phone, "@") { if len(*phone) <= 15 { @@ -201,7 +217,7 @@ func handler(rawEvt interface{}) { img := evt.Message.GetImageMessage() if img != nil { - path, err := DownloadMedia(config.PathStorages, img) + path, err := ExtractMedia(config.PathStorages, img) if err != nil { log.Errorf("Failed to download image: %v", err) } else { @@ -270,9 +286,11 @@ func forwardToWebhook(evt *events.Message) error { audioMedia := evt.Message.GetAudioMessage() documentMedia := evt.Message.GetDocumentMessage() - message := evt.Message.GetConversation() + var message evtMessage + message.Text = evt.Message.GetConversation() + message.ID = evt.Info.ID if extendedMessage := evt.Message.ExtendedTextMessage.GetText(); extendedMessage != "" { - message = extendedMessage + message.Text = extendedMessage } var quotedmessage any @@ -289,62 +307,62 @@ func forwardToWebhook(evt *events.Message) error { } } - var reactionMessage any + var waReaction *evtReaction if evt.Message.ReactionMessage != nil { - reactionMessage = *evt.Message.ReactionMessage.Text + waReaction.Message = evt.Message.ReactionMessage.GetText() + waReaction.ID = evt.Message.ReactionMessage.GetKey().GetId() } body := map[string]interface{}{ - "audio": audioMedia, - "contact": evt.Message.GetContactMessage(), - "document": documentMedia, - "forwarded": forwarded, - "from": evt.Info.SourceString(), - "image": imageMedia, - "list": evt.Message.GetListMessage(), - "live_location": evt.Message.GetLiveLocationMessage(), - "location": evt.Message.GetLocationMessage(), - "message": message, - "message_id": evt.Info.ID, - "order": evt.Message.GetOrderMessage(), - "pushname": evt.Info.PushName, - "quoted_message": quotedmessage, - "reaction_message": reactionMessage, - "sticker": stickerMedia, - "video": videoMedia, - "view_once": evt.Message.GetViewOnceMessage(), + "audio": audioMedia, + "contact": evt.Message.GetContactMessage(), + "document": documentMedia, + "forwarded": forwarded, + "from": evt.Info.SourceString(), + "image": imageMedia, + "list": evt.Message.GetListMessage(), + "live_location": evt.Message.GetLiveLocationMessage(), + "location": evt.Message.GetLocationMessage(), + "message": message, + "order": evt.Message.GetOrderMessage(), + "pushname": evt.Info.PushName, + "quoted_message": quotedmessage, + "reaction": waReaction, + "sticker": stickerMedia, + "video": videoMedia, + "view_once": evt.Message.GetViewOnceMessage(), } if imageMedia != nil { - path, err := DownloadMedia(config.PathMedia, imageMedia) + path, err := ExtractMedia(config.PathMedia, imageMedia) if err != nil { return pkgError.WebhookError(fmt.Sprintf("Failed to download image: %v", err)) } body["image"] = path } if stickerMedia != nil { - path, err := DownloadMedia(config.PathMedia, stickerMedia) + path, err := ExtractMedia(config.PathMedia, stickerMedia) if err != nil { return pkgError.WebhookError(fmt.Sprintf("Failed to download sticker: %v", err)) } body["sticker"] = path } if videoMedia != nil { - path, err := DownloadMedia(config.PathMedia, videoMedia) + path, err := ExtractMedia(config.PathMedia, videoMedia) if err != nil { return pkgError.WebhookError(fmt.Sprintf("Failed to download video: %v", err)) } body["video"] = path } if audioMedia != nil { - path, err := DownloadMedia(config.PathMedia, audioMedia) + path, err := ExtractMedia(config.PathMedia, audioMedia) if err != nil { return pkgError.WebhookError(fmt.Sprintf("Failed to download audio: %v", err)) } body["audio"] = path } if documentMedia != nil { - path, err := DownloadMedia(config.PathMedia, documentMedia) + path, err := ExtractMedia(config.PathMedia, documentMedia) if err != nil { return pkgError.WebhookError(fmt.Sprintf("Failed to download document: %v", err)) } @@ -390,37 +408,39 @@ func extractPhoneNumber(jid string) string { return "" } -// DownloadMedia is a helper function to download media from whatsapp -func DownloadMedia(storageLocation string, mediaFile whatsmeow.DownloadableMessage) (path string, err error) { +// ExtractMedia is a helper function to extract media from whatsapp +func ExtractMedia(storageLocation string, mediaFile whatsmeow.DownloadableMessage) (extractedMedia ExtractedMedia, err error) { if mediaFile == nil { logrus.Info("Skip download because data is nil") - return "", nil + return extractedMedia, nil } data, err := cli.Download(mediaFile) if err != nil { - return path, err + return extractedMedia, err } - var mimeType string switch media := mediaFile.(type) { case *waProto.ImageMessage: - mimeType = media.GetMimetype() + extractedMedia.MimeType = media.GetMimetype() + extractedMedia.Caption = media.GetCaption() case *waProto.AudioMessage: - mimeType = media.GetMimetype() + extractedMedia.MimeType = media.GetMimetype() case *waProto.VideoMessage: - mimeType = media.GetMimetype() + extractedMedia.MimeType = media.GetMimetype() + extractedMedia.Caption = media.GetCaption() case *waProto.StickerMessage: - mimeType = media.GetMimetype() + extractedMedia.MimeType = media.GetMimetype() case *waProto.DocumentMessage: - mimeType = media.GetMimetype() + extractedMedia.MimeType = media.GetMimetype() + extractedMedia.Caption = media.GetCaption() } - extensions, _ := mime.ExtensionsByType(mimeType) - path = fmt.Sprintf("%s/%d-%s%s", storageLocation, time.Now().Unix(), uuid.NewString(), extensions[0]) - err = os.WriteFile(path, data, 0600) + extensions, _ := mime.ExtensionsByType(extractedMedia.MimeType) + extractedMedia.MediaPath = fmt.Sprintf("%s/%d-%s%s", storageLocation, time.Now().Unix(), uuid.NewString(), extensions[0]) + err = os.WriteFile(extractedMedia.MediaPath, data, 0600) if err != nil { - return path, err + return extractedMedia, err } - return path, nil + return extractedMedia, nil }