From 240965f18d16be5e3c88d35f3918afeaf53c12e5 Mon Sep 17 00:00:00 2001 From: evgendn Date: Mon, 22 Jul 2019 23:10:18 +0500 Subject: [PATCH] Add stickers methods --- bot.go | 300 ++++++++++++++++++++++++++++++++++++++-------------- go.sum | 1 + stickers.go | 17 +++ util.go | 2 +- 4 files changed, 237 insertions(+), 83 deletions(-) diff --git a/bot.go b/bot.go index a1f925f..979df33 100644 --- a/bot.go +++ b/bot.go @@ -91,14 +91,14 @@ type Settings struct { type Update struct { ID int `json:"update_id"` - Message *Message `json:"message,omitempty"` - EditedMessage *Message `json:"edited_message,omitempty"` - ChannelPost *Message `json:"channel_post,omitempty"` - EditedChannelPost *Message `json:"edited_channel_post,omitempty"` - Callback *Callback `json:"callback_query,omitempty"` - Query *Query `json:"inline_query,omitempty"` + Message *Message `json:"message,omitempty"` + EditedMessage *Message `json:"edited_message,omitempty"` + ChannelPost *Message `json:"channel_post,omitempty"` + EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + Callback *Callback `json:"callback_query,omitempty"` + Query *Query `json:"inline_query,omitempty"` ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"` - PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` + PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` } // ChosenInlineResult represents a result of an inline query that was chosen @@ -106,11 +106,10 @@ type Update struct { type ChosenInlineResult struct { From User `json:"from"` Location *Location `json:"location,omitempty"` - ResultID string `json:"result_id"` - Query string `json:"query"` + ResultID string `json:"result_id"` + Query string `json:"query"` // Inline messages only! MessageID string `json:"inline_message_id"` - } type PreCheckoutQuery struct { @@ -744,121 +743,121 @@ func (b *Bot) EditCaption(originalMsg Editable, caption string) (*Message, error // bot.EditMedia(msg, &tb.Video{File: tb.FromURL("http://video.mp4")}); // func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...interface{}) (*Message, error) { - var mediaRepr string; - var jsonRepr []byte; - var thumb *Photo; + var mediaRepr string + var jsonRepr []byte + var thumb *Photo - file := make(map[string]File); + file := make(map[string]File) - f := inputMedia.MediaFile(); + f := inputMedia.MediaFile() if f.InCloud() { - mediaRepr = f.FileID; + mediaRepr = f.FileID } else if f.FileURL != "" { - mediaRepr = f.FileURL; + mediaRepr = f.FileURL } else if f.OnDisk() || f.FileReader != nil { - s := f.FileLocal; - if (f.FileReader != nil) { - s = "0"; + s := f.FileLocal + if f.FileReader != nil { + s = "0" } - mediaRepr = "attach://" + s; - file[s] = *f; + mediaRepr = "attach://" + s + file[s] = *f } else { return nil, errors.Errorf( - "telebot: can't edit media, it doesn't exist anywhere"); + "telebot: can't edit media, it doesn't exist anywhere") } type FileJson struct { // All types. - Type string `json:"type"` - Caption string `json:"caption"` - Media string `json:"media"` + Type string `json:"type"` + Caption string `json:"caption"` + Media string `json:"media"` // Video. - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - SupportsStreaming bool `json:"supports_streaming,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + SupportsStreaming bool `json:"supports_streaming,omitempty"` // Video and audio. - Duration int `json:"duration,omitempty"` + Duration int `json:"duration,omitempty"` // Document. - FileName string `json:"file_name"` + FileName string `json:"file_name"` // Document, video and audio. - Thumbnail string `json:"thumb,omitempty"` - MIME string `json:"mime_type,omitempty"` + Thumbnail string `json:"thumb,omitempty"` + MIME string `json:"mime_type,omitempty"` // Audio. - Title string `json:"title,omitempty"` - Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` + Performer string `json:"performer,omitempty"` } - resultMedia := &FileJson {Media: mediaRepr}; + resultMedia := &FileJson{Media: mediaRepr} switch y := inputMedia.(type) { - case *Photo: - resultMedia.Type = "photo"; - resultMedia.Caption = y.Caption; - case *Video: - resultMedia.Type = "video"; - resultMedia.Caption = y.Caption; - resultMedia.Width = y.Width; - resultMedia.Height = y.Height; - resultMedia.Duration = y.Duration; - resultMedia.SupportsStreaming = y.SupportsStreaming; - resultMedia.MIME = y.MIME; - thumb = y.Thumbnail; - if thumb != nil { - resultMedia.Thumbnail = "attach://thumb"; - } - case *Document: - resultMedia.Type = "document"; - resultMedia.Caption = y.Caption; - resultMedia.FileName = y.FileName; - resultMedia.MIME = y.MIME; - thumb = y.Thumbnail; - if thumb != nil { - resultMedia.Thumbnail = "attach://thumb"; - } - case *Audio: - resultMedia.Type = "audio"; - resultMedia.Caption = y.Caption; - resultMedia.Duration = y.Duration; - resultMedia.MIME = y.MIME; - resultMedia.Title = y.Title; - resultMedia.Performer = y.Performer; - default: - return nil, errors.Errorf("telebot: inputMedia entry is not valid"); + case *Photo: + resultMedia.Type = "photo" + resultMedia.Caption = y.Caption + case *Video: + resultMedia.Type = "video" + resultMedia.Caption = y.Caption + resultMedia.Width = y.Width + resultMedia.Height = y.Height + resultMedia.Duration = y.Duration + resultMedia.SupportsStreaming = y.SupportsStreaming + resultMedia.MIME = y.MIME + thumb = y.Thumbnail + if thumb != nil { + resultMedia.Thumbnail = "attach://thumb" + } + case *Document: + resultMedia.Type = "document" + resultMedia.Caption = y.Caption + resultMedia.FileName = y.FileName + resultMedia.MIME = y.MIME + thumb = y.Thumbnail + if thumb != nil { + resultMedia.Thumbnail = "attach://thumb" + } + case *Audio: + resultMedia.Type = "audio" + resultMedia.Caption = y.Caption + resultMedia.Duration = y.Duration + resultMedia.MIME = y.MIME + resultMedia.Title = y.Title + resultMedia.Performer = y.Performer + default: + return nil, errors.Errorf("telebot: inputMedia entry is not valid") } - messageID, chatID := message.MessageSig(); + messageID, chatID := message.MessageSig() - jsonRepr, _ = json.Marshal(resultMedia); - params := map[string]string{}; - params["media"] = string(jsonRepr); + jsonRepr, _ = json.Marshal(resultMedia) + params := map[string]string{} + params["media"] = string(jsonRepr) // If inline message. if chatID == 0 { - params["inline_message_id"] = messageID; + params["inline_message_id"] = messageID } else { - params["chat_id"] = strconv.FormatInt(chatID, 10); - params["message_id"] = messageID; + params["chat_id"] = strconv.FormatInt(chatID, 10) + params["message_id"] = messageID } if thumb != nil { - file["thumb"] = *thumb.MediaFile(); + file["thumb"] = *thumb.MediaFile() } - sendOpts := extractOptions(options); - embedSendOptions(params, sendOpts); + sendOpts := extractOptions(options) + embedSendOptions(params, sendOpts) - respJSON, err := b.sendFiles("editMessageMedia", file, params); + respJSON, err := b.sendFiles("editMessageMedia", file, params) if err != nil { - return nil, err; + return nil, err } - return extractMsgResponse(respJSON); + return extractMsgResponse(respJSON) } // Delete removes the message, including service messages, @@ -1054,6 +1053,7 @@ func (b *Bot) GetFile(file *File) (io.ReadCloser, error) { return resp.Body, nil } + // StopLiveLocation should be called to stop broadcasting live message location // before Location.LivePeriod expires. // @@ -1357,3 +1357,139 @@ func (b *Bot) FileURLByID(fileID string) (string, error) { } return fmt.Sprintf("%s/file/bot%s/%s", b.URL, b.Token, f.FilePath), nil } + +// UploadStickerFile returns uploaded File on success. +func (b *Bot) UploadStickerFile(userID int, pngSticker *File) (*File, error) { + files := map[string]File{ + "png_sticker": *pngSticker, + } + params := map[string]string{ + "user_id": strconv.Itoa(userID), + } + + respJSON, err := b.sendFiles("uploadStickerFile", files, params) + if err != nil { + return nil, err + } + + var resp struct { + Ok bool + Result File + Description string + } + + err = json.Unmarshal(respJSON, &resp) + if err != nil { + return nil, err + } + + if !resp.Ok { + return nil, errors.Errorf("api error: %s", resp.Description) + } + + return &resp.Result, nil +} + +// GetStickerSet returns StickerSet on success. +func (b *Bot) GetStickerSet(name string) (*StickerSet, error) { + respJSON, err := b.Raw("getStickerSet", map[string]string{"name": name}) + if err != nil { + return nil, err + } + + var resp struct { + Ok bool + Description string + Result *StickerSet + } + err = json.Unmarshal(respJSON, &resp) + if err != nil { + return nil, err + } + + if !resp.Ok { + return nil, errors.Errorf("api error: %s", resp.Description) + } + + return resp.Result, nil +} + +// CreateNewStickerSet creates new sticker set. +func (b *Bot) CreateNewStickerSet(sp StickerSetParams, containsMasks bool, maskPosition MaskPosition) error { + files := map[string]File{ + "png_sticker": *sp.PngSticker, + } + params := map[string]string{ + "user_id": strconv.Itoa(sp.UserID), + "name": sp.Name, + "title": sp.Title, + "emojis": sp.Emojis, + } + + if containsMasks { + mp, err := json.Marshal(&maskPosition) + if err != nil { + return err + } + params["mask_position"] = string(mp) + } + + respJSON, err := b.sendFiles("createNewStickerSet", files, params) + if err != nil { + return err + } + + return extractOkResponse(respJSON) +} + +// AddStickerToSet adds new sticker to existing sticker set. +func (b *Bot) AddStickerToSet(sp StickerSetParams, maskPosition MaskPosition) error { + files := map[string]File{ + "png_sticker": *sp.PngSticker, + } + params := map[string]string{ + "user_id": strconv.Itoa(sp.UserID), + "name": sp.Name, + "title": sp.Title, + "emojis": sp.Emojis, + } + + if maskPosition != (MaskPosition{}) { + mp, err := json.Marshal(&maskPosition) + if err != nil { + return err + } + params["mask_position"] = string(mp) + } + + respJSON, err := b.sendFiles("addStickerToSet", files, params) + if err != nil { + return err + } + + return extractOkResponse(respJSON) +} + +// SetStickerPositionInSet moves a sticker in set to a specific position. +func (b *Bot) SetStickerPositionInSet(sticker string, position int) error { + params := map[string]string{ + "sticker": sticker, + "position": strconv.Itoa(position), + } + respJSON, err := b.Raw("setStickerPositionInSet", params) + if err != nil { + return err + } + + return extractOkResponse(respJSON) +} + +// DeleteStickerFromSet deletes sticker from set created by the bot. +func (b *Bot) DeleteStickerFromSet(sticker string) error { + respJSON, err := b.Raw("deleteStickerFromSet", map[string]string{"sticker": sticker}) + if err != nil { + return err + } + + return extractOkResponse(respJSON) +} diff --git a/go.sum b/go.sum index 6db13ab..f29ab35 100644 --- a/go.sum +++ b/go.sum @@ -1 +1,2 @@ +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/stickers.go b/stickers.go index 5795327..7c5caff 100644 --- a/stickers.go +++ b/stickers.go @@ -13,6 +13,14 @@ type Sticker struct { MaskPosition *MaskPosition `json:"mask_position,omitempty"` } +// StickerSet represents a sticker set +type StickerSet struct { + Name string `json:"name"` + Title string `json:"title"` + ContainsMasks bool `json:"contains_masks"` + Stickers []Sticker `json:"stickers"` +} + // MaskPosition describes the position on faces where // a mask should be placed by default. type MaskPosition struct { @@ -21,3 +29,12 @@ type MaskPosition struct { YShift float32 `json:"y_shift"` Scale float32 `json:"scale"` } + +// StickerSetParams describes the payload in creating new sticker set api-method. +type StickerSetParams struct { + UserID int + Name string + Title string + PngSticker *File + Emojis string +} diff --git a/util.go b/util.go index 67b76c8..6c2c1b5 100644 --- a/util.go +++ b/util.go @@ -2,8 +2,8 @@ package telebot import ( "encoding/json" - "strconv" "log" + "strconv" "github.com/pkg/errors" )