Merge master into develop.
commit
23ed97b145
|
@ -1,2 +1,3 @@
|
||||||
.idea/
|
.idea/
|
||||||
coverage.out
|
coverage.out
|
||||||
|
tmp/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.4
|
- '1.10'
|
||||||
|
- '1.11'
|
||||||
- tip
|
- tip
|
16
README.md
16
README.md
|
@ -3,10 +3,6 @@
|
||||||
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
||||||
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
||||||
|
|
||||||
All methods have been added, and all features should be available.
|
|
||||||
If you want a feature that hasn't been added yet or something is broken,
|
|
||||||
open an issue and I'll see what I can do.
|
|
||||||
|
|
||||||
All methods are fairly self explanatory, and reading the godoc page should
|
All methods are fairly self explanatory, and reading the godoc page should
|
||||||
explain everything. If something isn't clear, open an issue or submit
|
explain everything. If something isn't clear, open an issue or submit
|
||||||
a pull request.
|
a pull request.
|
||||||
|
@ -21,6 +17,9 @@ you want to ask questions or discuss development.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
First, ensure the library is installed and up to date by running
|
||||||
|
`go get -u github.com/go-telegram-bot-api/telegram-bot-api`.
|
||||||
|
|
||||||
This is a very simple bot that just displays any gotten updates,
|
This is a very simple bot that just displays any gotten updates,
|
||||||
then replies it to that chat.
|
then replies it to that chat.
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ func main() {
|
||||||
updates, err := bot.GetUpdatesChan(u)
|
updates, err := bot.GetUpdatesChan(u)
|
||||||
|
|
||||||
for update := range updates {
|
for update := range updates {
|
||||||
if update.Message == nil {
|
if update.Message == nil { // ignore any non-Message Updates
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +62,11 @@ func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki)
|
||||||
|
with detailed information on how to do many differen kinds of things.
|
||||||
|
It's a great place to get started on using keyboards, commands, or other
|
||||||
|
kinds of reply markup.
|
||||||
|
|
||||||
If you need to use webhooks (if you wish to run on Google App Engine),
|
If you need to use webhooks (if you wish to run on Google App Engine),
|
||||||
you may use a slightly different method.
|
you may use a slightly different method.
|
||||||
|
|
||||||
|
@ -98,7 +102,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.LastErrorDate != 0 {
|
if info.LastErrorDate != 0 {
|
||||||
log.Printf("failed to set webhook: %s", info.LastErrorMessage)
|
log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
updates := bot.ListenForWebhook("/" + bot.Token)
|
updates := bot.ListenForWebhook("/" + bot.Token)
|
||||||
|
|
113
bot.go
113
bot.go
|
@ -9,7 +9,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -28,6 +27,7 @@ type BotAPI struct {
|
||||||
|
|
||||||
Self User `json:"-"`
|
Self User `json:"-"`
|
||||||
Client *http.Client `json:"-"`
|
Client *http.Client `json:"-"`
|
||||||
|
shutdownChannel chan interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBotAPI creates a new BotAPI instance.
|
// NewBotAPI creates a new BotAPI instance.
|
||||||
|
@ -46,6 +46,7 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
||||||
Token: token,
|
Token: token,
|
||||||
Client: client,
|
Client: client,
|
||||||
Buffer: 100,
|
Buffer: 100,
|
||||||
|
shutdownChannel: make(chan interface{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
self, err := bot.GetMe()
|
self, err := bot.GetMe()
|
||||||
|
@ -394,6 +395,12 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
select {
|
||||||
|
case <-bot.shutdownChannel:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
updates, err := bot.GetUpdates(config)
|
updates, err := bot.GetUpdates(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -404,17 +411,22 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
if update.UpdateID >= config.Offset {
|
|
||||||
config.Offset = update.UpdateID + 1
|
|
||||||
ch <- update
|
ch <- update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopReceivingUpdates stops the go routine which receives updates
|
||||||
|
func (bot *BotAPI) StopReceivingUpdates() {
|
||||||
|
if bot.Debug {
|
||||||
|
log.Println("Stopping the update receiver routine...")
|
||||||
|
}
|
||||||
|
close(bot.shutdownChannel)
|
||||||
|
}
|
||||||
|
|
||||||
// ListenForWebhook registers a http handler for a webhook.
|
// ListenForWebhook registers a http handler for a webhook.
|
||||||
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
||||||
ch := make(chan Update, bot.Buffer)
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
@ -519,6 +531,99 @@ func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error)
|
||||||
return member, err
|
return member, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnbanChatMember unbans a user from a chat. Note that this only will work
|
||||||
|
// in supergroups and channels, and requires the bot to be an admin.
|
||||||
|
func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername != "" {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
}
|
||||||
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
return bot.MakeRequest("unbanChatMember", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestrictChatMember to restrict a user in a supergroup. The bot must be an
|
||||||
|
//administrator in the supergroup for this to work and must have the
|
||||||
|
//appropriate admin rights. Pass True for all boolean parameters to lift
|
||||||
|
//restrictions from a user. Returns True on success.
|
||||||
|
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername != "" {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
}
|
||||||
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
if config.CanSendMessages != nil {
|
||||||
|
v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
|
||||||
|
}
|
||||||
|
if config.CanSendMediaMessages != nil {
|
||||||
|
v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
|
||||||
|
}
|
||||||
|
if config.CanSendOtherMessages != nil {
|
||||||
|
v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
|
||||||
|
}
|
||||||
|
if config.CanAddWebPagePreviews != nil {
|
||||||
|
v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
|
||||||
|
}
|
||||||
|
if config.UntilDate != 0 {
|
||||||
|
v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
return bot.MakeRequest("restrictChatMember", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromoteChatMember add admin rights to user
|
||||||
|
func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername != "" {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
}
|
||||||
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
if config.CanChangeInfo != nil {
|
||||||
|
v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
|
||||||
|
}
|
||||||
|
if config.CanPostMessages != nil {
|
||||||
|
v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
|
||||||
|
}
|
||||||
|
if config.CanEditMessages != nil {
|
||||||
|
v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
|
||||||
|
}
|
||||||
|
if config.CanDeleteMessages != nil {
|
||||||
|
v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
|
||||||
|
}
|
||||||
|
if config.CanInviteUsers != nil {
|
||||||
|
v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
|
||||||
|
}
|
||||||
|
if config.CanRestrictMembers != nil {
|
||||||
|
v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
|
||||||
|
}
|
||||||
|
if config.CanPinMessages != nil {
|
||||||
|
v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
|
||||||
|
}
|
||||||
|
if config.CanPromoteMembers != nil {
|
||||||
|
v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
|
||||||
|
}
|
||||||
|
|
||||||
|
return bot.MakeRequest("promoteChatMember", v)
|
||||||
|
}
|
||||||
|
|
||||||
// GetGameHighScores allows you to get the high scores for a game.
|
// GetGameHighScores allows you to get the high scores for a game.
|
||||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||||
v, _ := config.values()
|
v, _ := config.values()
|
||||||
|
|
20
bot_test.go
20
bot_test.go
|
@ -476,16 +476,12 @@ func TestSetWebhookWithCert(t *testing.T) {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := bot.GetWebhookInfo()
|
_, err = bot.GetWebhookInfo()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.LastErrorDate != 0 {
|
|
||||||
t.Errorf("failed to set webhook: %s", info.LastErrorMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.Request(tgbotapi.RemoveWebhookConfig{})
|
bot.Request(tgbotapi.RemoveWebhookConfig{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,6 +525,20 @@ func TestUpdatesChan(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendWithMediaGroup(t *testing.T) {
|
||||||
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
|
cfg := tgbotapi.NewMediaGroup(ChatID, []interface{}{
|
||||||
|
tgbotapi.NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
|
||||||
|
tgbotapi.NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
|
||||||
|
tgbotapi.NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
|
||||||
|
})
|
||||||
|
_, err := bot.Request(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleNewBotAPI() {
|
func ExampleNewBotAPI() {
|
||||||
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
|
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
93
configs.go
93
configs.go
|
@ -244,6 +244,7 @@ func (config ForwardConfig) method() string {
|
||||||
type PhotoConfig struct {
|
type PhotoConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params returns a map[string]string representation of PhotoConfig.
|
// Params returns a map[string]string representation of PhotoConfig.
|
||||||
|
@ -252,6 +253,9 @@ func (config PhotoConfig) params() (map[string]string, error) {
|
||||||
|
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
params["caption"] = config.Caption
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
|
@ -267,7 +271,11 @@ func (config PhotoConfig) values() (url.Values, error) {
|
||||||
v.Add(config.name(), config.FileID)
|
v.Add(config.name(), config.FileID)
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +293,7 @@ func (config PhotoConfig) method() string {
|
||||||
type AudioConfig struct {
|
type AudioConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
Duration int
|
Duration int
|
||||||
Performer string
|
Performer string
|
||||||
Title string
|
Title string
|
||||||
|
@ -310,6 +319,9 @@ func (config AudioConfig) values() (url.Values, error) {
|
||||||
}
|
}
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -331,6 +343,9 @@ func (config AudioConfig) params() (map[string]string, error) {
|
||||||
}
|
}
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
params["caption"] = config.Caption
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
|
@ -350,6 +365,7 @@ func (config AudioConfig) method() string {
|
||||||
type DocumentConfig struct {
|
type DocumentConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
// values returns a url.Values representation of DocumentConfig.
|
// values returns a url.Values representation of DocumentConfig.
|
||||||
|
@ -362,6 +378,9 @@ func (config DocumentConfig) values() (url.Values, error) {
|
||||||
v.Add(config.name(), config.FileID)
|
v.Add(config.name(), config.FileID)
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -373,6 +392,9 @@ func (config DocumentConfig) params() (map[string]string, error) {
|
||||||
|
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
params["caption"] = config.Caption
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
|
@ -427,6 +449,7 @@ type VideoConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
Duration int
|
Duration int
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
// values returns a url.Values representation of VideoConfig.
|
// values returns a url.Values representation of VideoConfig.
|
||||||
|
@ -442,6 +465,9 @@ func (config VideoConfig) values() (url.Values, error) {
|
||||||
}
|
}
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -453,6 +479,9 @@ func (config VideoConfig) params() (map[string]string, error) {
|
||||||
|
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
params["caption"] = config.Caption
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
|
@ -468,6 +497,59 @@ func (config VideoConfig) method() string {
|
||||||
return "sendVideo"
|
return "sendVideo"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnimationConfig contains information about a SendAnimation request.
|
||||||
|
type AnimationConfig struct {
|
||||||
|
BaseFile
|
||||||
|
Duration int
|
||||||
|
Caption string
|
||||||
|
ParseMode string
|
||||||
|
}
|
||||||
|
|
||||||
|
// values returns a url.Values representation of AnimationConfig.
|
||||||
|
func (config AnimationConfig) values() (url.Values, error) {
|
||||||
|
v, err := config.BaseChat.values()
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Add(config.name(), config.FileID)
|
||||||
|
if config.Duration != 0 {
|
||||||
|
v.Add("duration", strconv.Itoa(config.Duration))
|
||||||
|
}
|
||||||
|
if config.Caption != "" {
|
||||||
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// params returns a map[string]string representation of AnimationConfig.
|
||||||
|
func (config AnimationConfig) params() (map[string]string, error) {
|
||||||
|
params, _ := config.BaseFile.params()
|
||||||
|
|
||||||
|
if config.Caption != "" {
|
||||||
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// name returns the field name for the Animation.
|
||||||
|
func (config AnimationConfig) name() string {
|
||||||
|
return "animation"
|
||||||
|
}
|
||||||
|
|
||||||
|
// method returns Telegram API method name for sending Animation.
|
||||||
|
func (config AnimationConfig) method() string {
|
||||||
|
return "sendAnimation"
|
||||||
|
}
|
||||||
|
|
||||||
// VideoNoteConfig contains information about a SendVideoNote request.
|
// VideoNoteConfig contains information about a SendVideoNote request.
|
||||||
type VideoNoteConfig struct {
|
type VideoNoteConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
|
@ -523,6 +605,7 @@ func (config VideoNoteConfig) method() string {
|
||||||
type VoiceConfig struct {
|
type VoiceConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
Duration int
|
Duration int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,6 +622,9 @@ func (config VoiceConfig) values() (url.Values, error) {
|
||||||
}
|
}
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -553,6 +639,9 @@ func (config VoiceConfig) params() (map[string]string, error) {
|
||||||
}
|
}
|
||||||
if config.Caption != "" {
|
if config.Caption != "" {
|
||||||
params["caption"] = config.Caption
|
params["caption"] = config.Caption
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
params["parse_mode"] = config.ParseMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
|
@ -831,12 +920,16 @@ func (config EditMessageTextConfig) method() string {
|
||||||
type EditMessageCaptionConfig struct {
|
type EditMessageCaptionConfig struct {
|
||||||
BaseEdit
|
BaseEdit
|
||||||
Caption string
|
Caption string
|
||||||
|
ParseMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config EditMessageCaptionConfig) values() (url.Values, error) {
|
func (config EditMessageCaptionConfig) values() (url.Values, error) {
|
||||||
v, _ := config.BaseEdit.values()
|
v, _ := config.BaseEdit.values()
|
||||||
|
|
||||||
v.Add("caption", config.Caption)
|
v.Add("caption", config.Caption)
|
||||||
|
if config.ParseMode != "" {
|
||||||
|
v.Add("parse_mode", config.ParseMode)
|
||||||
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
63
helpers.go
63
helpers.go
|
@ -1,7 +1,6 @@
|
||||||
package tgbotapi
|
package tgbotapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,6 +18,14 @@ func NewMessage(chatID int64, text string) MessageConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDeleteMessage creates a request to delete a message.
|
||||||
|
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
|
||||||
|
return DeleteMessageConfig{
|
||||||
|
ChatID: chatID,
|
||||||
|
MessageID: messageID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewMessageToChannel creates a new Message that is sent to a channel
|
// NewMessageToChannel creates a new Message that is sent to a channel
|
||||||
// by username.
|
// by username.
|
||||||
//
|
//
|
||||||
|
@ -194,6 +201,35 @@ func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAnimationUpload creates a new animation uploader.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, file is a string path to the file,
|
||||||
|
// FileReader, or FileBytes.
|
||||||
|
func NewAnimationUpload(chatID int64, file interface{}) AnimationConfig {
|
||||||
|
return AnimationConfig{
|
||||||
|
BaseFile: BaseFile{
|
||||||
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
|
File: file,
|
||||||
|
UseExisting: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAnimationShare shares an existing animation.
|
||||||
|
// You may use this to reshare an existing animation without reuploading it.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, fileID is the ID of the animation
|
||||||
|
// already uploaded.
|
||||||
|
func NewAnimationShare(chatID int64, fileID string) AnimationConfig {
|
||||||
|
return AnimationConfig{
|
||||||
|
BaseFile: BaseFile{
|
||||||
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
|
FileID: fileID,
|
||||||
|
UseExisting: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewVideoNoteUpload creates a new video note uploader.
|
// NewVideoNoteUpload creates a new video note uploader.
|
||||||
//
|
//
|
||||||
// chatID is where to send it, file is a string path to the file,
|
// chatID is where to send it, file is a string path to the file,
|
||||||
|
@ -254,6 +290,31 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMediaGroup creates a new media group. Files should be an array of
|
||||||
|
// two to ten InputMediaPhoto or InputMediaVideo.
|
||||||
|
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
||||||
|
return MediaGroupConfig{
|
||||||
|
ChatID: chatID,
|
||||||
|
Media: files,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||||
|
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
||||||
|
return InputMediaPhoto{
|
||||||
|
Type: "photo",
|
||||||
|
Media: media,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||||
|
func NewInputMediaVideo(media string) InputMediaVideo {
|
||||||
|
return InputMediaVideo{
|
||||||
|
Type: "video",
|
||||||
|
Media: media,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewContact allows you to send a shared contact.
|
// NewContact allows you to send a shared contact.
|
||||||
func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig {
|
func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig {
|
||||||
return ContactConfig{
|
return ContactConfig{
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package tgbotapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
stdlog "log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BotLogger is an interface that represents the required methods to log data.
|
||||||
|
//
|
||||||
|
// Instead of requiring the standard logger, we can just specify the methods we
|
||||||
|
// use and allow users to pass anything that implements these.
|
||||||
|
type BotLogger interface {
|
||||||
|
Println(v ...interface{})
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
var log BotLogger = stdlog.New(os.Stderr, "", stdlog.LstdFlags)
|
||||||
|
|
||||||
|
// SetLogger specifies the logger that the package should use.
|
||||||
|
func SetLogger(logger BotLogger) error {
|
||||||
|
if logger == nil {
|
||||||
|
return errors.New("logger is nil")
|
||||||
|
}
|
||||||
|
log = logger
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,315 @@
|
||||||
|
package tgbotapi
|
||||||
|
|
||||||
|
// PassportRequestInfoConfig allows you to request passport info
|
||||||
|
type PassportRequestInfoConfig struct {
|
||||||
|
BotID int `json:"bot_id"`
|
||||||
|
Scope *PassportScope `json:"scope"`
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportScopeElement supports using one or one of several elements.
|
||||||
|
type PassportScopeElement interface {
|
||||||
|
ScopeType() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportScope is the requested scopes of data.
|
||||||
|
type PassportScope struct {
|
||||||
|
V int `json:"v"`
|
||||||
|
Data []PassportScopeElement `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportScopeElementOneOfSeveral allows you to request any one of the
|
||||||
|
// requested documents.
|
||||||
|
type PassportScopeElementOneOfSeveral struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScopeType is the scope type.
|
||||||
|
func (eo *PassportScopeElementOneOfSeveral) ScopeType() string {
|
||||||
|
return "one_of"
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportScopeElementOne requires the specified element be provided.
|
||||||
|
type PassportScopeElementOne struct {
|
||||||
|
Type string `json:"type"` // One of “personal_details”, “passport”, “driver_license”, “identity_card”, “internal_passport”, “address”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”, “phone_number”, “email”
|
||||||
|
Selfie bool `json:"selfie"`
|
||||||
|
Translation bool `json:"translation"`
|
||||||
|
NativeNames bool `json:"native_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScopeType is the scope type.
|
||||||
|
func (eo *PassportScopeElementOne) ScopeType() string {
|
||||||
|
return "one"
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// PassportData contains information about Telegram Passport data shared with
|
||||||
|
// the bot by the user.
|
||||||
|
PassportData struct {
|
||||||
|
// Array with information about documents and other Telegram Passport
|
||||||
|
// elements that was shared with the bot
|
||||||
|
Data []EncryptedPassportElement `json:"data"`
|
||||||
|
|
||||||
|
// Encrypted credentials required to decrypt the data
|
||||||
|
Credentials *EncryptedCredentials `json:"credentials"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportFile represents a file uploaded to Telegram Passport. Currently all
|
||||||
|
// Telegram Passport files are in JPEG format when decrypted and don't exceed
|
||||||
|
// 10MB.
|
||||||
|
PassportFile struct {
|
||||||
|
// Unique identifier for this file
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
|
||||||
|
// File size
|
||||||
|
FileSize int `json:"file_size"`
|
||||||
|
|
||||||
|
// Unix time when the file was uploaded
|
||||||
|
FileDate int64 `json:"file_date"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptedPassportElement contains information about documents or other
|
||||||
|
// Telegram Passport elements shared with the bot by the user.
|
||||||
|
EncryptedPassportElement struct {
|
||||||
|
// Element type.
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Base64-encoded encrypted Telegram Passport element data provided by
|
||||||
|
// the user, available for "personal_details", "passport",
|
||||||
|
// "driver_license", "identity_card", "identity_passport" and "address"
|
||||||
|
// types. Can be decrypted and verified using the accompanying
|
||||||
|
// EncryptedCredentials.
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
|
||||||
|
// User's verified phone number, available only for "phone_number" type
|
||||||
|
PhoneNumber string `json:"phone_number,omitempty"`
|
||||||
|
|
||||||
|
// User's verified email address, available only for "email" type
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
|
||||||
|
// Array of encrypted files with documents provided by the user,
|
||||||
|
// available for "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration" and "temporary_registration" types. Files can
|
||||||
|
// be decrypted and verified using the accompanying EncryptedCredentials.
|
||||||
|
Files []PassportFile `json:"files,omitempty"`
|
||||||
|
|
||||||
|
// Encrypted file with the front side of the document, provided by the
|
||||||
|
// user. Available for "passport", "driver_license", "identity_card" and
|
||||||
|
// "internal_passport". The file can be decrypted and verified using the
|
||||||
|
// accompanying EncryptedCredentials.
|
||||||
|
FrontSide *PassportFile `json:"front_side,omitempty"`
|
||||||
|
|
||||||
|
// Encrypted file with the reverse side of the document, provided by the
|
||||||
|
// user. Available for "driver_license" and "identity_card". The file can
|
||||||
|
// be decrypted and verified using the accompanying EncryptedCredentials.
|
||||||
|
ReverseSide *PassportFile `json:"reverse_side,omitempty"`
|
||||||
|
|
||||||
|
// Encrypted file with the selfie of the user holding a document,
|
||||||
|
// provided by the user; available for "passport", "driver_license",
|
||||||
|
// "identity_card" and "internal_passport". The file can be decrypted
|
||||||
|
// and verified using the accompanying EncryptedCredentials.
|
||||||
|
Selfie *PassportFile `json:"selfie,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptedCredentials contains data required for decrypting and
|
||||||
|
// authenticating EncryptedPassportElement. See the Telegram Passport
|
||||||
|
// Documentation for a complete description of the data decryption and
|
||||||
|
// authentication processes.
|
||||||
|
EncryptedCredentials struct {
|
||||||
|
// Base64-encoded encrypted JSON-serialized data with unique user's
|
||||||
|
// payload, data hashes and secrets required for EncryptedPassportElement
|
||||||
|
// decryption and authentication
|
||||||
|
Data string `json:"data"`
|
||||||
|
|
||||||
|
// Base64-encoded data hash for data authentication
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
|
||||||
|
// Base64-encoded secret, encrypted with the bot's public RSA key,
|
||||||
|
// required for data decryption
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementError represents an error in the Telegram Passport element
|
||||||
|
// which was submitted that should be resolved by the user.
|
||||||
|
PassportElementError interface{}
|
||||||
|
|
||||||
|
// PassportElementErrorDataField represents an issue in one of the data
|
||||||
|
// fields that was provided by the user. The error is considered resolved
|
||||||
|
// when the field's value changes.
|
||||||
|
PassportElementErrorDataField struct {
|
||||||
|
// Error source, must be data
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the error, one
|
||||||
|
// of "personal_details", "passport", "driver_license", "identity_card",
|
||||||
|
// "internal_passport", "address"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Name of the data field which has the error
|
||||||
|
FieldName string `json:"field_name"`
|
||||||
|
|
||||||
|
// Base64-encoded data hash
|
||||||
|
DataHash string `json:"data_hash"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementErrorFrontSide represents an issue with the front side of
|
||||||
|
// a document. The error is considered resolved when the file with the front
|
||||||
|
// side of the document changes.
|
||||||
|
PassportElementErrorFrontSide struct {
|
||||||
|
// Error source, must be front_side
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "passport", "driver_license", "identity_card", "internal_passport"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the front side of the document
|
||||||
|
FileHash string `json:"file_hash"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementErrorReverseSide represents an issue with the reverse side
|
||||||
|
// of a document. The error is considered resolved when the file with reverse
|
||||||
|
// side of the document changes.
|
||||||
|
PassportElementErrorReverseSide struct {
|
||||||
|
// Error source, must be reverse_side
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "driver_license", "identity_card"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the reverse side of the document
|
||||||
|
FileHash string `json:"file_hash"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementErrorSelfie represents an issue with the selfie with a
|
||||||
|
// document. The error is considered resolved when the file with the selfie
|
||||||
|
// changes.
|
||||||
|
PassportElementErrorSelfie struct {
|
||||||
|
// Error source, must be selfie
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "passport", "driver_license", "identity_card", "internal_passport"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the selfie
|
||||||
|
FileHash string `json:"file_hash"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementErrorFile represents an issue with a document scan. The
|
||||||
|
// error is considered resolved when the file with the document scan changes.
|
||||||
|
PassportElementErrorFile struct {
|
||||||
|
// Error source, must be file
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration", "temporary_registration"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Base64-encoded file hash
|
||||||
|
FileHash string `json:"file_hash"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassportElementErrorFiles represents an issue with a list of scans. The
|
||||||
|
// error is considered resolved when the list of files containing the scans
|
||||||
|
// changes.
|
||||||
|
PassportElementErrorFiles struct {
|
||||||
|
// Error source, must be files
|
||||||
|
Source string `json:"source"`
|
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration", "temporary_registration"
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// List of base64-encoded file hashes
|
||||||
|
FileHashes []string `json:"file_hashes"`
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credentials contains encrypted data.
|
||||||
|
Credentials struct {
|
||||||
|
Data SecureData `json:"secure_data"`
|
||||||
|
// Nonce the same nonce given in the request
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecureData is a map of the fields and their encrypted values.
|
||||||
|
SecureData map[string]*SecureValue
|
||||||
|
// PersonalDetails *SecureValue `json:"personal_details"`
|
||||||
|
// Passport *SecureValue `json:"passport"`
|
||||||
|
// InternalPassport *SecureValue `json:"internal_passport"`
|
||||||
|
// DriverLicense *SecureValue `json:"driver_license"`
|
||||||
|
// IdentityCard *SecureValue `json:"identity_card"`
|
||||||
|
// Address *SecureValue `json:"address"`
|
||||||
|
// UtilityBill *SecureValue `json:"utility_bill"`
|
||||||
|
// BankStatement *SecureValue `json:"bank_statement"`
|
||||||
|
// RentalAgreement *SecureValue `json:"rental_agreement"`
|
||||||
|
// PassportRegistration *SecureValue `json:"passport_registration"`
|
||||||
|
// TemporaryRegistration *SecureValue `json:"temporary_registration"`
|
||||||
|
|
||||||
|
// SecureValue contains encrypted values for a SecureData item.
|
||||||
|
SecureValue struct {
|
||||||
|
Data *DataCredentials `json:"data"`
|
||||||
|
FrontSide *FileCredentials `json:"front_side"`
|
||||||
|
ReverseSide *FileCredentials `json:"reverse_side"`
|
||||||
|
Selfie *FileCredentials `json:"selfie"`
|
||||||
|
Translation []*FileCredentials `json:"translation"`
|
||||||
|
Files []*FileCredentials `json:"files"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataCredentials contains information required to decrypt data.
|
||||||
|
DataCredentials struct {
|
||||||
|
// DataHash checksum of encrypted data
|
||||||
|
DataHash string `json:"data_hash"`
|
||||||
|
// Secret of encrypted data
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileCredentials contains information required to decrypt files.
|
||||||
|
FileCredentials struct {
|
||||||
|
// FileHash checksum of encrypted data
|
||||||
|
FileHash string `json:"file_hash"`
|
||||||
|
// Secret of encrypted data
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PersonalDetails https://core.telegram.org/passport#personaldetails
|
||||||
|
PersonalDetails struct {
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
MiddleName string `json:"middle_name"`
|
||||||
|
BirthDate string `json:"birth_date"`
|
||||||
|
Gender string `json:"gender"`
|
||||||
|
CountryCode string `json:"country_code"`
|
||||||
|
ResidenceCountryCode string `json:"residence_country_code"`
|
||||||
|
FirstNameNative string `json:"first_name_native"`
|
||||||
|
LastNameNative string `json:"last_name_native"`
|
||||||
|
MiddleNameNative string `json:"middle_name_native"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDDocumentData https://core.telegram.org/passport#iddocumentdata
|
||||||
|
IDDocumentData struct {
|
||||||
|
DocumentNumber string `json:"document_no"`
|
||||||
|
ExpiryDate string `json:"expiry_date"`
|
||||||
|
}
|
||||||
|
)
|
33
types.go
33
types.go
|
@ -151,6 +151,7 @@ type Message struct {
|
||||||
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
|
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
|
||||||
Audio *Audio `json:"audio"` // optional
|
Audio *Audio `json:"audio"` // optional
|
||||||
Document *Document `json:"document"` // optional
|
Document *Document `json:"document"` // optional
|
||||||
|
Animation *ChatAnimation `json:"animation"` // optional
|
||||||
Game *Game `json:"game"` // optional
|
Game *Game `json:"game"` // optional
|
||||||
Photo *[]PhotoSize `json:"photo"` // optional
|
Photo *[]PhotoSize `json:"photo"` // optional
|
||||||
Sticker *Sticker `json:"sticker"` // optional
|
Sticker *Sticker `json:"sticker"` // optional
|
||||||
|
@ -174,6 +175,7 @@ type Message struct {
|
||||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
PinnedMessage *Message `json:"pinned_message"` // optional
|
||||||
Invoice *Invoice `json:"invoice"` // optional
|
Invoice *Invoice `json:"invoice"` // optional
|
||||||
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
|
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
|
||||||
|
PassportData *PassportData `json:"passport_data,omitempty"` // optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time converts the message timestamp into a Time.
|
// Time converts the message timestamp into a Time.
|
||||||
|
@ -308,6 +310,25 @@ type MaskPosition struct {
|
||||||
XShift float32 `json:"x_shift"`
|
XShift float32 `json:"x_shift"`
|
||||||
YShift float32 `json:"y_shift"`
|
YShift float32 `json:"y_shift"`
|
||||||
Scale float32 `json:"scale"`
|
Scale float32 `json:"scale"`
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||||
|
Emoji string `json:"emoji"` // optional
|
||||||
|
FileSize int `json:"file_size"` // optional
|
||||||
|
SetName string `json:"set_name"` // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatAnimation contains information about an animation.
|
||||||
|
type ChatAnimation struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||||
|
FileName string `json:"file_name"` // optional
|
||||||
|
MimeType string `json:"mime_type"` // optional
|
||||||
|
FileSize int `json:"file_size"` // optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video contains information about a video.
|
// Video contains information about a video.
|
||||||
|
@ -806,6 +827,7 @@ type InputMediaPhoto struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Media string `json:"media"`
|
Media string `json:"media"`
|
||||||
Caption string `json:"caption"`
|
Caption string `json:"caption"`
|
||||||
|
ParseMode string `json:"parse_mode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputMediaVideo is a video to send as part of a media group.
|
// InputMediaVideo is a video to send as part of a media group.
|
||||||
|
@ -814,10 +836,13 @@ type InputMediaPhoto struct {
|
||||||
type InputMediaVideo struct {
|
type InputMediaVideo struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Media string `json:"media"`
|
Media string `json:"media"`
|
||||||
Caption string `json:"caption,omitempty"`
|
// thumb intentionally missing as it is not currently compatible
|
||||||
Width int `json:"width,omitempty"`
|
Caption string `json:"caption"`
|
||||||
Height int `json:"height,omitempty"`
|
ParseMode string `json:"parse_mode"`
|
||||||
Duration int `json:"duration,omitempty"`
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
SupportsStreaming bool `json:"supports_streaming"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error is an error containing extra information returned by the Telegram API.
|
// Error is an error containing extra information returned by the Telegram API.
|
||||||
|
|
Loading…
Reference in New Issue