forked from jshiffer/matterbridge
Update telegram-bot-api to v5 (#1660)
This commit is contained in:
parent
3893a035be
commit
02e3d7852b
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
"github.com/42wim/matterbridge/bridge/helper"
|
"github.com/42wim/matterbridge/bridge/helper"
|
||||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message {
|
func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message {
|
||||||
@ -94,7 +94,7 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
|
|||||||
// handleUsername handles the correct setting of the username
|
// handleUsername handles the correct setting of the username
|
||||||
func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) {
|
func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) {
|
||||||
if message.From != nil {
|
if message.From != nil {
|
||||||
rmsg.UserID = strconv.Itoa(message.From.ID)
|
rmsg.UserID = strconv.FormatInt(message.From.ID, 10)
|
||||||
if b.GetBool("UseFirstName") {
|
if b.GetBool("UseFirstName") {
|
||||||
rmsg.Username = message.From.FirstName
|
rmsg.Username = message.From.FirstName
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
|||||||
rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
|
rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
|
||||||
// channels don't have (always?) user information. see #410
|
// channels don't have (always?) user information. see #410
|
||||||
if message.From != nil {
|
if message.From != nil {
|
||||||
rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.Itoa(message.From.ID), b.General)
|
rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.FormatInt(message.From.ID, 10), b.General)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
|
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
|
||||||
@ -180,18 +180,21 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
|||||||
// handleDownloadAvatar downloads the avatar of userid from channel
|
// handleDownloadAvatar downloads the avatar of userid from channel
|
||||||
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
|
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
|
||||||
// logs an error message if it fails
|
// logs an error message if it fails
|
||||||
func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
|
func (b *Btelegram) handleDownloadAvatar(userid int64, channel string) {
|
||||||
rmsg := config.Message{
|
rmsg := config.Message{
|
||||||
Username: "system",
|
Username: "system",
|
||||||
Text: "avatar",
|
Text: "avatar",
|
||||||
Channel: channel,
|
Channel: channel,
|
||||||
Account: b.Account,
|
Account: b.Account,
|
||||||
UserID: strconv.Itoa(userid),
|
UserID: strconv.FormatInt(userid, 10),
|
||||||
Event: config.EventAvatarDownload,
|
Event: config.EventAvatarDownload,
|
||||||
Extra: make(map[string][]interface{}),
|
Extra: make(map[string][]interface{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok {
|
if _, ok := b.avatarMap[strconv.FormatInt(userid, 10)]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
|
photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
|
b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
|
||||||
@ -200,7 +203,7 @@ func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
|
|||||||
if len(photos.Photos) > 0 {
|
if len(photos.Photos) > 0 {
|
||||||
photo := photos.Photos[0][0]
|
photo := photos.Photos[0][0]
|
||||||
url := b.getFileDirectURL(photo.FileID)
|
url := b.getFileDirectURL(photo.FileID)
|
||||||
name := strconv.Itoa(userid) + ".png"
|
name := strconv.FormatInt(userid, 10) + ".png"
|
||||||
b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
|
b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
|
||||||
|
|
||||||
err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
|
err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
|
||||||
@ -217,7 +220,6 @@ func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
|
|||||||
b.Remote <- rmsg
|
b.Remote <- rmsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
|
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
|
||||||
format := b.GetString("MediaConvertTgs")
|
format := b.GetString("MediaConvertTgs")
|
||||||
@ -272,7 +274,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
|
|||||||
name = message.Document.FileName
|
name = message.Document.FileName
|
||||||
text = " " + message.Document.FileName + " : " + url
|
text = " " + message.Document.FileName + " : " + url
|
||||||
case message.Photo != nil:
|
case message.Photo != nil:
|
||||||
photos := *message.Photo
|
photos := message.Photo
|
||||||
size = photos[len(photos)-1].FileSize
|
size = photos[len(photos)-1].FileSize
|
||||||
text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true)
|
text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true)
|
||||||
}
|
}
|
||||||
@ -331,11 +333,15 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err
|
|||||||
if msg.ID == "" {
|
if msg.ID == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msgid, err := strconv.Atoi(msg.ID)
|
msgid, err := strconv.Atoi(msg.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid})
|
|
||||||
|
cfg := tgbotapi.NewDeleteMessage(chatid, msgid)
|
||||||
|
_, err = b.c.Send(cfg)
|
||||||
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,23 +389,23 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
|
|||||||
}
|
}
|
||||||
switch filepath.Ext(fi.Name) {
|
switch filepath.Ext(fi.Name) {
|
||||||
case ".jpg", ".jpe", ".png":
|
case ".jpg", ".jpe", ".png":
|
||||||
pc := tgbotapi.NewPhotoUpload(chatid, file)
|
pc := tgbotapi.NewPhoto(chatid, file)
|
||||||
pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||||
c = pc
|
c = pc
|
||||||
case ".mp4", ".m4v":
|
case ".mp4", ".m4v":
|
||||||
vc := tgbotapi.NewVideoUpload(chatid, file)
|
vc := tgbotapi.NewVideo(chatid, file)
|
||||||
vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||||
c = vc
|
c = vc
|
||||||
case ".mp3", ".oga":
|
case ".mp3", ".oga":
|
||||||
ac := tgbotapi.NewAudioUpload(chatid, file)
|
ac := tgbotapi.NewAudio(chatid, file)
|
||||||
ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||||
c = ac
|
c = ac
|
||||||
case ".ogg":
|
case ".ogg":
|
||||||
voc := tgbotapi.NewVoiceUpload(chatid, file)
|
voc := tgbotapi.NewVoice(chatid, file)
|
||||||
voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||||
c = voc
|
c = voc
|
||||||
default:
|
default:
|
||||||
dc := tgbotapi.NewDocumentUpload(chatid, file)
|
dc := tgbotapi.NewDocument(chatid, file)
|
||||||
dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||||
c = dc
|
c = dc
|
||||||
}
|
}
|
||||||
@ -439,7 +445,7 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
|
|||||||
indexMovedBy := 0
|
indexMovedBy := 0
|
||||||
|
|
||||||
// for now only do URL replacements
|
// for now only do URL replacements
|
||||||
for _, e := range *message.Entities {
|
for _, e := range message.Entities {
|
||||||
if e.Type == "text_link" {
|
if e.Type == "text_link" {
|
||||||
url, err := e.ParseURL()
|
url, err := e.ParseURL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge"
|
"github.com/42wim/matterbridge/bridge"
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
"github.com/42wim/matterbridge/bridge/helper"
|
"github.com/42wim/matterbridge/bridge/helper"
|
||||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,11 +49,7 @@ func (b *Btelegram) Connect() error {
|
|||||||
}
|
}
|
||||||
u := tgbotapi.NewUpdate(0)
|
u := tgbotapi.NewUpdate(0)
|
||||||
u.Timeout = 60
|
u.Timeout = 60
|
||||||
updates, err := b.c.GetUpdatesChan(u)
|
updates := b.c.GetUpdatesChan(u)
|
||||||
if err != nil {
|
|
||||||
b.Log.Debugf("%#v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b.Log.Info("Connection succeeded")
|
b.Log.Info("Connection succeeded")
|
||||||
go b.handleRecv(updates)
|
go b.handleRecv(updates)
|
||||||
return nil
|
return nil
|
||||||
|
3
go.mod
3
go.mod
@ -10,7 +10,7 @@ require (
|
|||||||
github.com/d5/tengo/v2 v2.10.0
|
github.com/d5/tengo/v2 v2.10.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/fsnotify/fsnotify v1.5.1
|
github.com/fsnotify/fsnotify v1.5.1
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0
|
||||||
github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc
|
github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc
|
||||||
github.com/google/gops v0.3.22
|
github.com/google/gops v0.3.22
|
||||||
github.com/gorilla/schema v1.2.0
|
github.com/gorilla/schema v1.2.0
|
||||||
@ -109,7 +109,6 @@ require (
|
|||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
|
||||||
github.com/tinylib/msgp v1.1.6 // indirect
|
github.com/tinylib/msgp v1.1.6 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
|
6
go.sum
6
go.sum
@ -393,8 +393,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
|||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 h1:FdZThbRF0R+2qgyBl3KCVNWWBmKm68E+stT3rnQ02Ww=
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0 h1:BtndtqqCQfPsL2uMkYmduOip1+dPcSmh40l82mBUPKk=
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81/go.mod h1:lDm2E64X4OjFdBUA4hlN4mEvbSitvhJdKw7rsA8KHgI=
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
|
||||||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||||
@ -1223,8 +1223,6 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
|
|||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg=
|
github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg=
|
||||||
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
|
||||||
github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
|
github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
|
||||||
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
||||||
github.com/tidwall/gjson v1.9.2/go.mod h1:2tcKM/KQ/GjiTN7mfTL/HdNmef9Q6AZLaSK2RdfvSjw=
|
github.com/tidwall/gjson v1.9.2/go.mod h1:2tcKM/KQ/GjiTN7mfTL/HdNmef9Q6AZLaSK2RdfvSjw=
|
||||||
|
8
vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
generated
vendored
8
vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- '1.10'
|
|
||||||
- '1.11'
|
|
||||||
- '1.12'
|
|
||||||
- '1.13'
|
|
||||||
- tip
|
|
1014
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
1014
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1279
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
1279
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
File diff suppressed because it is too large
Load Diff
990
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
990
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
@ -1,990 +0,0 @@
|
|||||||
package tgbotapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// APIResponse is a response from the Telegram API with the result
|
|
||||||
// stored raw.
|
|
||||||
type APIResponse struct {
|
|
||||||
Ok bool `json:"ok"`
|
|
||||||
Result json.RawMessage `json:"result"`
|
|
||||||
ErrorCode int `json:"error_code"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Parameters *ResponseParameters `json:"parameters"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseParameters are various errors that can be returned in APIResponse.
|
|
||||||
type ResponseParameters struct {
|
|
||||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
|
||||||
RetryAfter int `json:"retry_after"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is an update response, from GetUpdates.
|
|
||||||
type Update struct {
|
|
||||||
UpdateID int `json:"update_id"`
|
|
||||||
Message *Message `json:"message"`
|
|
||||||
EditedMessage *Message `json:"edited_message"`
|
|
||||||
ChannelPost *Message `json:"channel_post"`
|
|
||||||
EditedChannelPost *Message `json:"edited_channel_post"`
|
|
||||||
InlineQuery *InlineQuery `json:"inline_query"`
|
|
||||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
|
|
||||||
CallbackQuery *CallbackQuery `json:"callback_query"`
|
|
||||||
ShippingQuery *ShippingQuery `json:"shipping_query"`
|
|
||||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatesChannel is the channel for getting updates.
|
|
||||||
type UpdatesChannel <-chan Update
|
|
||||||
|
|
||||||
// Clear discards all unprocessed incoming updates.
|
|
||||||
func (ch UpdatesChannel) Clear() {
|
|
||||||
for len(ch) != 0 {
|
|
||||||
<-ch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User is a user on Telegram.
|
|
||||||
type User struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
UserName string `json:"username"` // optional
|
|
||||||
LanguageCode string `json:"language_code"` // optional
|
|
||||||
IsBot bool `json:"is_bot"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// String displays a simple text version of a user.
|
|
||||||
//
|
|
||||||
// It is normally a user's username, but falls back to a first/last
|
|
||||||
// name as available.
|
|
||||||
func (u *User) String() string {
|
|
||||||
if u == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if u.UserName != "" {
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
name := u.FirstName
|
|
||||||
if u.LastName != "" {
|
|
||||||
name += " " + u.LastName
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// GroupChat is a group chat.
|
|
||||||
type GroupChat struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatPhoto represents a chat photo.
|
|
||||||
type ChatPhoto struct {
|
|
||||||
SmallFileID string `json:"small_file_id"`
|
|
||||||
BigFileID string `json:"big_file_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chat contains information about the place a message was sent.
|
|
||||||
type Chat struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Title string `json:"title"` // optional
|
|
||||||
UserName string `json:"username"` // optional
|
|
||||||
FirstName string `json:"first_name"` // optional
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
|
|
||||||
Photo *ChatPhoto `json:"photo"`
|
|
||||||
Description string `json:"description,omitempty"` // optional
|
|
||||||
InviteLink string `json:"invite_link,omitempty"` // optional
|
|
||||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivate returns if the Chat is a private conversation.
|
|
||||||
func (c Chat) IsPrivate() bool {
|
|
||||||
return c.Type == "private"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsGroup returns if the Chat is a group.
|
|
||||||
func (c Chat) IsGroup() bool {
|
|
||||||
return c.Type == "group"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSuperGroup returns if the Chat is a supergroup.
|
|
||||||
func (c Chat) IsSuperGroup() bool {
|
|
||||||
return c.Type == "supergroup"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsChannel returns if the Chat is a channel.
|
|
||||||
func (c Chat) IsChannel() bool {
|
|
||||||
return c.Type == "channel"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatConfig returns a ChatConfig struct for chat related methods.
|
|
||||||
func (c Chat) ChatConfig() ChatConfig {
|
|
||||||
return ChatConfig{ChatID: c.ID}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message is returned by almost every request, and contains data about
|
|
||||||
// almost anything.
|
|
||||||
type Message struct {
|
|
||||||
MessageID int `json:"message_id"`
|
|
||||||
From *User `json:"from"` // optional
|
|
||||||
Date int `json:"date"`
|
|
||||||
Chat *Chat `json:"chat"`
|
|
||||||
ForwardFrom *User `json:"forward_from"` // optional
|
|
||||||
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
|
|
||||||
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
|
|
||||||
ForwardDate int `json:"forward_date"` // optional
|
|
||||||
ReplyToMessage *Message `json:"reply_to_message"` // optional
|
|
||||||
EditDate int `json:"edit_date"` // optional
|
|
||||||
Text string `json:"text"` // optional
|
|
||||||
Entities *[]MessageEntity `json:"entities"` // optional
|
|
||||||
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
|
|
||||||
Audio *Audio `json:"audio"` // optional
|
|
||||||
Document *Document `json:"document"` // optional
|
|
||||||
Animation *ChatAnimation `json:"animation"` // optional
|
|
||||||
Game *Game `json:"game"` // optional
|
|
||||||
Photo *[]PhotoSize `json:"photo"` // optional
|
|
||||||
Sticker *Sticker `json:"sticker"` // optional
|
|
||||||
Video *Video `json:"video"` // optional
|
|
||||||
VideoNote *VideoNote `json:"video_note"` // optional
|
|
||||||
Voice *Voice `json:"voice"` // optional
|
|
||||||
Caption string `json:"caption"` // optional
|
|
||||||
Contact *Contact `json:"contact"` // optional
|
|
||||||
Location *Location `json:"location"` // optional
|
|
||||||
Venue *Venue `json:"venue"` // optional
|
|
||||||
NewChatMembers *[]User `json:"new_chat_members"` // optional
|
|
||||||
LeftChatMember *User `json:"left_chat_member"` // optional
|
|
||||||
NewChatTitle string `json:"new_chat_title"` // optional
|
|
||||||
NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
|
|
||||||
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
|
|
||||||
GroupChatCreated bool `json:"group_chat_created"` // optional
|
|
||||||
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
|
|
||||||
ChannelChatCreated bool `json:"channel_chat_created"` // optional
|
|
||||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
|
||||||
MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
|
|
||||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
|
||||||
Invoice *Invoice `json:"invoice"` // optional
|
|
||||||
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
|
|
||||||
PassportData *PassportData `json:"passport_data,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time converts the message timestamp into a Time.
|
|
||||||
func (m *Message) Time() time.Time {
|
|
||||||
return time.Unix(int64(m.Date), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand returns true if message starts with a "bot_command" entity.
|
|
||||||
func (m *Message) IsCommand() bool {
|
|
||||||
if m.Entities == nil || len(*m.Entities) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
return entity.Offset == 0 && entity.IsCommand()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command checks if the message was a command and if it was, returns the
|
|
||||||
// command. If the Message was not a command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// If the command contains the at name syntax, it is removed. Use
|
|
||||||
// CommandWithAt() if you do not want that.
|
|
||||||
func (m *Message) Command() string {
|
|
||||||
command := m.CommandWithAt()
|
|
||||||
|
|
||||||
if i := strings.Index(command, "@"); i != -1 {
|
|
||||||
command = command[:i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return command
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandWithAt checks if the message was a command and if it was, returns the
|
|
||||||
// command. If the Message was not a command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// If the command contains the at name syntax, it is not removed. Use Command()
|
|
||||||
// if you want that.
|
|
||||||
func (m *Message) CommandWithAt() string {
|
|
||||||
if !m.IsCommand() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand() checks that the message begins with a bot_command entity
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
return m.Text[1:entity.Length]
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandArguments checks if the message was a command and if it was,
|
|
||||||
// returns all text after the command name. If the Message was not a
|
|
||||||
// command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// Note: The first character after the command name is omitted:
|
|
||||||
// - "/foo bar baz" yields "bar baz", not " bar baz"
|
|
||||||
// - "/foo-bar baz" yields "bar baz", too
|
|
||||||
// Even though the latter is not a command conforming to the spec, the API
|
|
||||||
// marks "/foo" as command entity.
|
|
||||||
func (m *Message) CommandArguments() string {
|
|
||||||
if !m.IsCommand() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand() checks that the message begins with a bot_command entity
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
if len(m.Text) == entity.Length {
|
|
||||||
return "" // The command makes up the whole message
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.Text[entity.Length+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageEntity contains information about data in a Message.
|
|
||||||
type MessageEntity struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Offset int `json:"offset"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
URL string `json:"url"` // optional
|
|
||||||
User *User `json:"user"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseURL attempts to parse a URL contained within a MessageEntity.
|
|
||||||
func (e MessageEntity) ParseURL() (*url.URL, error) {
|
|
||||||
if e.URL == "" {
|
|
||||||
return nil, errors.New(ErrBadURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.Parse(e.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsMention returns true if the type of the message entity is "mention" (@username).
|
|
||||||
func (e MessageEntity) IsMention() bool {
|
|
||||||
return e.Type == "mention"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsHashtag returns true if the type of the message entity is "hashtag".
|
|
||||||
func (e MessageEntity) IsHashtag() bool {
|
|
||||||
return e.Type == "hashtag"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand returns true if the type of the message entity is "bot_command".
|
|
||||||
func (e MessageEntity) IsCommand() bool {
|
|
||||||
return e.Type == "bot_command"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsUrl returns true if the type of the message entity is "url".
|
|
||||||
func (e MessageEntity) IsUrl() bool {
|
|
||||||
return e.Type == "url"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEmail returns true if the type of the message entity is "email".
|
|
||||||
func (e MessageEntity) IsEmail() bool {
|
|
||||||
return e.Type == "email"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsBold returns true if the type of the message entity is "bold" (bold text).
|
|
||||||
func (e MessageEntity) IsBold() bool {
|
|
||||||
return e.Type == "bold"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsItalic returns true if the type of the message entity is "italic" (italic text).
|
|
||||||
func (e MessageEntity) IsItalic() bool {
|
|
||||||
return e.Type == "italic"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCode returns true if the type of the message entity is "code" (monowidth string).
|
|
||||||
func (e MessageEntity) IsCode() bool {
|
|
||||||
return e.Type == "code"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPre returns true if the type of the message entity is "pre" (monowidth block).
|
|
||||||
func (e MessageEntity) IsPre() bool {
|
|
||||||
return e.Type == "pre"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL).
|
|
||||||
func (e MessageEntity) IsTextLink() bool {
|
|
||||||
return e.Type == "text_link"
|
|
||||||
}
|
|
||||||
|
|
||||||
// PhotoSize contains information about photos.
|
|
||||||
type PhotoSize struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio contains information about audio.
|
|
||||||
type Audio struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Performer string `json:"performer"` // optional
|
|
||||||
Title string `json:"title"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Document contains information about a document.
|
|
||||||
type Document struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
FileName string `json:"file_name"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sticker contains information about a sticker.
|
|
||||||
type Sticker struct {
|
|
||||||
FileUniqueID string `json:"file_unique_id"`
|
|
||||||
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
|
|
||||||
IsAnimated bool `json:"is_animated"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
type StickerSet struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
IsAnimated bool `json:"is_animated"`
|
|
||||||
ContainsMasks bool `json:"contains_masks"`
|
|
||||||
Stickers []Sticker `json:"stickers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
type Video struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// VideoNote contains information about a video.
|
|
||||||
type VideoNote struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Voice contains information about a voice.
|
|
||||||
type Voice struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contact contains information about a contact.
|
|
||||||
//
|
|
||||||
// Note that LastName and UserID may be empty.
|
|
||||||
type Contact struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
UserID int `json:"user_id"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Location contains information about a place.
|
|
||||||
type Location struct {
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Venue contains information about a venue, including its Location.
|
|
||||||
type Venue struct {
|
|
||||||
Location Location `json:"location"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
FoursquareID string `json:"foursquare_id"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserProfilePhotos contains a set of user profile photos.
|
|
||||||
type UserProfilePhotos struct {
|
|
||||||
TotalCount int `json:"total_count"`
|
|
||||||
Photos [][]PhotoSize `json:"photos"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// File contains information about a file to download from Telegram.
|
|
||||||
type File struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
FilePath string `json:"file_path"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link returns a full path to the download URL for a File.
|
|
||||||
//
|
|
||||||
// It requires the Bot Token to create the link.
|
|
||||||
func (f *File) Link(token string) string {
|
|
||||||
return fmt.Sprintf(FileEndpoint, token, f.FilePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
|
|
||||||
type ReplyKeyboardMarkup struct {
|
|
||||||
Keyboard [][]KeyboardButton `json:"keyboard"`
|
|
||||||
ResizeKeyboard bool `json:"resize_keyboard"` // optional
|
|
||||||
OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyboardButton is a button within a custom keyboard.
|
|
||||||
type KeyboardButton struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
RequestContact bool `json:"request_contact"`
|
|
||||||
RequestLocation bool `json:"request_location"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
|
|
||||||
type ReplyKeyboardHide struct {
|
|
||||||
HideKeyboard bool `json:"hide_keyboard"`
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
|
|
||||||
type ReplyKeyboardRemove struct {
|
|
||||||
RemoveKeyboard bool `json:"remove_keyboard"`
|
|
||||||
Selective bool `json:"selective"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
|
|
||||||
type InlineKeyboardMarkup struct {
|
|
||||||
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineKeyboardButton is a button within a custom keyboard for
|
|
||||||
// inline query responses.
|
|
||||||
//
|
|
||||||
// Note that some values are references as even an empty string
|
|
||||||
// will change behavior.
|
|
||||||
//
|
|
||||||
// CallbackGame, if set, MUST be first button in first row.
|
|
||||||
type InlineKeyboardButton struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
URL *string `json:"url,omitempty"` // optional
|
|
||||||
CallbackData *string `json:"callback_data,omitempty"` // optional
|
|
||||||
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
|
|
||||||
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` // optional
|
|
||||||
CallbackGame *CallbackGame `json:"callback_game,omitempty"` // optional
|
|
||||||
Pay bool `json:"pay,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackQuery is data sent when a keyboard button with callback data
|
|
||||||
// is clicked.
|
|
||||||
type CallbackQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Message *Message `json:"message"` // optional
|
|
||||||
InlineMessageID string `json:"inline_message_id"` // optional
|
|
||||||
ChatInstance string `json:"chat_instance"`
|
|
||||||
Data string `json:"data"` // optional
|
|
||||||
GameShortName string `json:"game_short_name"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForceReply allows the Bot to have users directly reply to it without
|
|
||||||
// additional interaction.
|
|
||||||
type ForceReply struct {
|
|
||||||
ForceReply bool `json:"force_reply"`
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatMember is information about a member in a chat.
|
|
||||||
type ChatMember struct {
|
|
||||||
User *User `json:"user"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
UntilDate int64 `json:"until_date,omitempty"` // optional
|
|
||||||
CanBeEdited bool `json:"can_be_edited,omitempty"` // optional
|
|
||||||
CanChangeInfo bool `json:"can_change_info,omitempty"` // optional
|
|
||||||
CanPostMessages bool `json:"can_post_messages,omitempty"` // optional
|
|
||||||
CanEditMessages bool `json:"can_edit_messages,omitempty"` // optional
|
|
||||||
CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // optional
|
|
||||||
CanInviteUsers bool `json:"can_invite_users,omitempty"` // optional
|
|
||||||
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional
|
|
||||||
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
|
|
||||||
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional
|
|
||||||
CanSendMessages bool `json:"can_send_messages,omitempty"` // optional
|
|
||||||
CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional
|
|
||||||
CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional
|
|
||||||
CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCreator returns if the ChatMember was the creator of the chat.
|
|
||||||
func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
|
|
||||||
|
|
||||||
// IsAdministrator returns if the ChatMember is a chat administrator.
|
|
||||||
func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
|
|
||||||
|
|
||||||
// IsMember returns if the ChatMember is a current member of the chat.
|
|
||||||
func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
|
|
||||||
|
|
||||||
// HasLeft returns if the ChatMember left the chat.
|
|
||||||
func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
|
|
||||||
|
|
||||||
// WasKicked returns if the ChatMember was kicked from the chat.
|
|
||||||
func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
|
|
||||||
|
|
||||||
// Game is a game within Telegram.
|
|
||||||
type Game struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Photo []PhotoSize `json:"photo"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
TextEntities []MessageEntity `json:"text_entities"`
|
|
||||||
Animation Animation `json:"animation"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animation is a GIF animation demonstrating the game.
|
|
||||||
type Animation struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Thumb PhotoSize `json:"thumb"`
|
|
||||||
FileName string `json:"file_name"`
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
FileSize int `json:"file_size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GameHighScore is a user's score and position on the leaderboard.
|
|
||||||
type GameHighScore struct {
|
|
||||||
Position int `json:"position"`
|
|
||||||
User User `json:"user"`
|
|
||||||
Score int `json:"score"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackGame is for starting a game in an inline keyboard button.
|
|
||||||
type CallbackGame struct{}
|
|
||||||
|
|
||||||
// WebhookInfo is information about a currently set webhook.
|
|
||||||
type WebhookInfo struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
HasCustomCertificate bool `json:"has_custom_certificate"`
|
|
||||||
PendingUpdateCount int `json:"pending_update_count"`
|
|
||||||
LastErrorDate int `json:"last_error_date"` // optional
|
|
||||||
LastErrorMessage string `json:"last_error_message"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSet returns true if a webhook is currently set.
|
|
||||||
func (info WebhookInfo) IsSet() bool {
|
|
||||||
return info.URL != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputMediaPhoto contains a photo for displaying as part of a media group.
|
|
||||||
type InputMediaPhoto struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputMediaVideo contains a video for displaying as part of a media group.
|
|
||||||
type InputMediaVideo struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
// thumb intentionally missing as it is not currently compatible
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
SupportsStreaming bool `json:"supports_streaming"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQuery is a Query from Telegram for an inline request.
|
|
||||||
type InlineQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Location *Location `json:"location"` // optional
|
|
||||||
Query string `json:"query"`
|
|
||||||
Offset string `json:"offset"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultArticle is an inline query response article.
|
|
||||||
type InlineQueryResultArticle struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
HideURL bool `json:"hide_url"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultPhoto is an inline query response photo.
|
|
||||||
type InlineQueryResultPhoto struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"photo_url"` // required
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
Width int `json:"photo_width"`
|
|
||||||
Height int `json:"photo_height"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedPhoto is an inline query response with cached photo.
|
|
||||||
type InlineQueryResultCachedPhoto struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
PhotoID string `json:"photo_file_id"` // required
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultGIF is an inline query response GIF.
|
|
||||||
type InlineQueryResultGIF struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"gif_url"` // required
|
|
||||||
ThumbURL string `json:"thumb_url"` // required
|
|
||||||
Width int `json:"gif_width,omitempty"`
|
|
||||||
Height int `json:"gif_height,omitempty"`
|
|
||||||
Duration int `json:"gif_duration,omitempty"`
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Caption string `json:"caption,omitempty"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedGIF is an inline query response with cached gif.
|
|
||||||
type InlineQueryResultCachedGIF struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
GifID string `json:"gif_file_id"` // required
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
|
|
||||||
type InlineQueryResultMPEG4GIF struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"mpeg4_url"` // required
|
|
||||||
Width int `json:"mpeg4_width"`
|
|
||||||
Height int `json:"mpeg4_height"`
|
|
||||||
Duration int `json:"mpeg4_duration"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedMpeg4Gif is an inline query response with cached
|
|
||||||
// H.264/MPEG-4 AVC video without sound gif.
|
|
||||||
type InlineQueryResultCachedMpeg4Gif struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
MGifID string `json:"mpeg4_file_id"` // required
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultVideo is an inline query response video.
|
|
||||||
type InlineQueryResultVideo struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"video_url"` // required
|
|
||||||
MimeType string `json:"mime_type"` // required
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Width int `json:"video_width"`
|
|
||||||
Height int `json:"video_height"`
|
|
||||||
Duration int `json:"video_duration"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedVideo is an inline query response with cached video.
|
|
||||||
type InlineQueryResultCachedVideo struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
VideoID string `json:"video_file_id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Description string `json:"description"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultAudio is an inline query response audio.
|
|
||||||
type InlineQueryResultAudio struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"audio_url"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Performer string `json:"performer"`
|
|
||||||
Duration int `json:"audio_duration"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedAudio is an inline query response with cached audio.
|
|
||||||
type InlineQueryResultCachedAudio struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
AudioID string `json:"audio_file_id"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultVoice is an inline query response voice.
|
|
||||||
type InlineQueryResultVoice struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"voice_url"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Duration int `json:"voice_duration"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedVoice is an inline query response with cached voice.
|
|
||||||
type InlineQueryResultCachedVoice struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
VoiceID string `json:"voice_file_id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultDocument is an inline query response document.
|
|
||||||
type InlineQueryResultDocument struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
URL string `json:"document_url"` // required
|
|
||||||
MimeType string `json:"mime_type"` // required
|
|
||||||
Description string `json:"description"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultCachedDocument is an inline query response with cached document.
|
|
||||||
type InlineQueryResultCachedDocument struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
DocumentID string `json:"document_file_id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultLocation is an inline query response location.
|
|
||||||
type InlineQueryResultLocation struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Latitude float64 `json:"latitude"` // required
|
|
||||||
Longitude float64 `json:"longitude"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultVenue is an inline query response venue.
|
|
||||||
type InlineQueryResultVenue struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Latitude float64 `json:"latitude"` // required
|
|
||||||
Longitude float64 `json:"longitude"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Address string `json:"address"` // required
|
|
||||||
FoursquareID string `json:"foursquare_id"`
|
|
||||||
FoursquareType string `json:"foursquare_type"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultGame is an inline query response game.
|
|
||||||
type InlineQueryResultGame struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
GameShortName string `json:"game_short_name"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChosenInlineResult is an inline query result chosen by a User
|
|
||||||
type ChosenInlineResult struct {
|
|
||||||
ResultID string `json:"result_id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Location *Location `json:"location"`
|
|
||||||
InlineMessageID string `json:"inline_message_id"`
|
|
||||||
Query string `json:"query"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputTextMessageContent contains text for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputTextMessageContent struct {
|
|
||||||
Text string `json:"message_text"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
DisableWebPagePreview bool `json:"disable_web_page_preview"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputLocationMessageContent contains a location for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputLocationMessageContent struct {
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputVenueMessageContent contains a venue for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputVenueMessageContent struct {
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
FoursquareID string `json:"foursquare_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputContactMessageContent contains a contact for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputContactMessageContent struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoice contains basic information about an invoice.
|
|
||||||
type Invoice struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
StartParameter string `json:"start_parameter"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LabeledPrice represents a portion of the price for goods or services.
|
|
||||||
type LabeledPrice struct {
|
|
||||||
Label string `json:"label"`
|
|
||||||
Amount int `json:"amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingAddress represents a shipping address.
|
|
||||||
type ShippingAddress struct {
|
|
||||||
CountryCode string `json:"country_code"`
|
|
||||||
State string `json:"state"`
|
|
||||||
City string `json:"city"`
|
|
||||||
StreetLine1 string `json:"street_line1"`
|
|
||||||
StreetLine2 string `json:"street_line2"`
|
|
||||||
PostCode string `json:"post_code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrderInfo represents information about an order.
|
|
||||||
type OrderInfo struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
PhoneNumber string `json:"phone_number,omitempty"`
|
|
||||||
Email string `json:"email,omitempty"`
|
|
||||||
ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingOption represents one shipping option.
|
|
||||||
type ShippingOption struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Prices *[]LabeledPrice `json:"prices"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuccessfulPayment contains basic information about a successful payment.
|
|
||||||
type SuccessfulPayment struct {
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
|
||||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
|
||||||
TelegramPaymentChargeID string `json:"telegram_payment_charge_id"`
|
|
||||||
ProviderPaymentChargeID string `json:"provider_payment_charge_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingQuery contains information about an incoming shipping query.
|
|
||||||
type ShippingQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingAddress *ShippingAddress `json:"shipping_address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PreCheckoutQuery contains information about an incoming pre-checkout query.
|
|
||||||
type PreCheckoutQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
|
||||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error is an error containing extra information returned by the Telegram API.
|
|
||||||
type Error struct {
|
|
||||||
Code int
|
|
||||||
Message string
|
|
||||||
ResponseParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Error) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
.idea/
|
.idea/
|
||||||
coverage.out
|
coverage.out
|
||||||
tmp/
|
tmp/
|
||||||
|
book/
|
@ -1,12 +1,14 @@
|
|||||||
# Golang bindings for the Telegram Bot API
|
# Golang bindings for the 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)
|
[![Go Reference](https://pkg.go.dev/badge/github.com/go-telegram-bot-api/telegram-bot-api/v5.svg)](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5)
|
||||||
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
[![Test](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml/badge.svg)](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml)
|
||||||
|
|
||||||
All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should
|
All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) 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.
|
||||||
|
|
||||||
|
There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev).
|
||||||
|
|
||||||
The scope of this project is just to provide a wrapper around the API
|
The scope of this project is just to provide a wrapper around the API
|
||||||
without any additional features. There are other projects for creating
|
without any additional features. There are other projects for creating
|
||||||
something with plugins and command handlers without having to design
|
something with plugins and command handlers without having to design
|
||||||
@ -18,7 +20,7 @@ you want to ask questions or discuss development.
|
|||||||
## Example
|
## Example
|
||||||
|
|
||||||
First, ensure the library is installed and up to date by running
|
First, ensure the library is installed and up to date by running
|
||||||
`go get -u github.com/go-telegram-bot-api/telegram-bot-api`.
|
`go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`.
|
||||||
|
|
||||||
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.
|
||||||
@ -29,7 +31,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -45,13 +47,10 @@ func main() {
|
|||||||
u := tgbotapi.NewUpdate(0)
|
u := tgbotapi.NewUpdate(0)
|
||||||
u.Timeout = 60
|
u.Timeout = 60
|
||||||
|
|
||||||
updates, err := bot.GetUpdatesChan(u)
|
updates := bot.GetUpdatesChan(u)
|
||||||
|
|
||||||
for update := range updates {
|
for update := range updates {
|
||||||
if update.Message == nil { // ignore any non-Message Updates
|
if update.Message != nil { // If we got a message
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
||||||
|
|
||||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
||||||
@ -60,13 +59,9 @@ func main() {
|
|||||||
bot.Send(msg)
|
bot.Send(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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 different 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.
|
||||||
|
|
||||||
@ -77,7 +72,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
"github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -90,17 +85,22 @@ func main() {
|
|||||||
|
|
||||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||||
|
|
||||||
_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
|
wh, _ := tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")
|
||||||
|
|
||||||
|
_, err = bot.SetWebhook(wh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := bot.GetWebhookInfo()
|
info, err := bot.GetWebhookInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.LastErrorDate != 0 {
|
if info.LastErrorDate != 0 {
|
||||||
log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
|
log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
updates := bot.ListenForWebhook("/" + bot.Token)
|
updates := bot.ListenForWebhook("/" + bot.Token)
|
||||||
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need, you may generate a self signed certficate, as this requires
|
If you need, you may generate a self-signed certificate, as this requires
|
||||||
HTTPS / TLS. The above example tells Telegram that this is your
|
HTTPS / TLS. The above example tells Telegram that this is your
|
||||||
certificate and that it should be trusted, even though it is not
|
certificate and that it should be trusted, even though it is not
|
||||||
properly signed.
|
properly signed.
|
9
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
generated
vendored
Normal file
9
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[book]
|
||||||
|
authors = ["Syfaro"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "docs"
|
||||||
|
title = "Go Telegram Bot API"
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api"
|
726
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
generated
vendored
Normal file
726
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
generated
vendored
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
// Package tgbotapi has functions and types used for interacting with
|
||||||
|
// the Telegram Bot API.
|
||||||
|
package tgbotapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPClient is the type needed for the bot to perform HTTP requests.
|
||||||
|
type HTTPClient interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BotAPI allows you to interact with the Telegram Bot API.
|
||||||
|
type BotAPI struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
Debug bool `json:"debug"`
|
||||||
|
Buffer int `json:"buffer"`
|
||||||
|
|
||||||
|
Self User `json:"-"`
|
||||||
|
Client HTTPClient `json:"-"`
|
||||||
|
shutdownChannel chan interface{}
|
||||||
|
|
||||||
|
apiEndpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotAPI creates a new BotAPI instance.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram.
|
||||||
|
func NewBotAPI(token string) (*BotAPI, error) {
|
||||||
|
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
|
||||||
|
// and allows you to pass API endpoint.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
|
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
|
||||||
|
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotAPIWithClient creates a new BotAPI instance
|
||||||
|
// and allows you to pass a http.Client.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
|
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
|
||||||
|
bot := &BotAPI{
|
||||||
|
Token: token,
|
||||||
|
Client: client,
|
||||||
|
Buffer: 100,
|
||||||
|
shutdownChannel: make(chan interface{}),
|
||||||
|
|
||||||
|
apiEndpoint: apiEndpoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
self, err := bot.GetMe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.Self = self
|
||||||
|
|
||||||
|
return bot, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance.
|
||||||
|
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
|
||||||
|
bot.apiEndpoint = apiEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildParams(in Params) url.Values {
|
||||||
|
if in == nil {
|
||||||
|
return url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := url.Values{}
|
||||||
|
|
||||||
|
for key, value := range in {
|
||||||
|
out.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRequest makes a request to a specific endpoint with our token.
|
||||||
|
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) {
|
||||||
|
if bot.Debug {
|
||||||
|
log.Printf("Endpoint: %s, params: %v\n", endpoint, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||||
|
|
||||||
|
values := buildParams(params)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", method, strings.NewReader(values.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return &APIResponse{}, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
resp, err := bot.Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var apiResp APIResponse
|
||||||
|
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||||
|
if err != nil {
|
||||||
|
return &apiResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bot.Debug {
|
||||||
|
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !apiResp.Ok {
|
||||||
|
var parameters ResponseParameters
|
||||||
|
|
||||||
|
if apiResp.Parameters != nil {
|
||||||
|
parameters = *apiResp.Parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, &Error{
|
||||||
|
Code: apiResp.ErrorCode,
|
||||||
|
Message: apiResp.Description,
|
||||||
|
ResponseParameters: parameters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
||||||
|
// If debug disabled, just decode http.Response.Body stream to APIResponse struct
|
||||||
|
// for efficient memory usage
|
||||||
|
func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) {
|
||||||
|
if !bot.Debug {
|
||||||
|
dec := json.NewDecoder(responseBody)
|
||||||
|
err := dec.Decode(resp)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if debug, read response body
|
||||||
|
data, err := ioutil.ReadAll(responseBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadFiles makes a request to the API with files.
|
||||||
|
func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) {
|
||||||
|
r, w := io.Pipe()
|
||||||
|
m := multipart.NewWriter(w)
|
||||||
|
|
||||||
|
// This code modified from the very helpful @HirbodBehnam
|
||||||
|
// https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473
|
||||||
|
go func() {
|
||||||
|
defer w.Close()
|
||||||
|
defer m.Close()
|
||||||
|
|
||||||
|
for field, value := range params {
|
||||||
|
if err := m.WriteField(field, value); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if file.Data.NeedsUpload() {
|
||||||
|
name, reader, err := file.Data.UploadData()
|
||||||
|
if err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
part, err := m.CreateFormFile(file.Name, name)
|
||||||
|
if err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.Copy(part, reader); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if closer, ok := reader.(io.ReadCloser); ok {
|
||||||
|
if err = closer.Close(); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value := file.Data.SendData()
|
||||||
|
|
||||||
|
if err := m.WriteField(file.Name, value); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if bot.Debug {
|
||||||
|
log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files))
|
||||||
|
}
|
||||||
|
|
||||||
|
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", method, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", m.FormDataContentType())
|
||||||
|
|
||||||
|
resp, err := bot.Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var apiResp APIResponse
|
||||||
|
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||||
|
if err != nil {
|
||||||
|
return &apiResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bot.Debug {
|
||||||
|
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !apiResp.Ok {
|
||||||
|
var parameters ResponseParameters
|
||||||
|
|
||||||
|
if apiResp.Parameters != nil {
|
||||||
|
parameters = *apiResp.Parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, &Error{
|
||||||
|
Message: apiResp.Description,
|
||||||
|
ResponseParameters: parameters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFileDirectURL returns direct URL to file
|
||||||
|
//
|
||||||
|
// It requires the FileID.
|
||||||
|
func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
|
||||||
|
file, err := bot.GetFile(FileConfig{fileID})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Link(bot.Token), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMe fetches the currently authenticated bot.
|
||||||
|
//
|
||||||
|
// This method is called upon creation to validate the token,
|
||||||
|
// and so you may get this data from BotAPI.Self without the need for
|
||||||
|
// another request.
|
||||||
|
func (bot *BotAPI) GetMe() (User, error) {
|
||||||
|
resp, err := bot.MakeRequest("getMe", nil)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var user User
|
||||||
|
err = json.Unmarshal(resp.Result, &user)
|
||||||
|
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMessageToMe returns true if message directed to this bot.
|
||||||
|
//
|
||||||
|
// It requires the Message.
|
||||||
|
func (bot *BotAPI) IsMessageToMe(message Message) bool {
|
||||||
|
return strings.Contains(message.Text, "@"+bot.Self.UserName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasFilesNeedingUpload(files []RequestFile) bool {
|
||||||
|
for _, file := range files {
|
||||||
|
if file.Data.NeedsUpload() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request sends a Chattable to Telegram, and returns the APIResponse.
|
||||||
|
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) {
|
||||||
|
params, err := c.params()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if t, ok := c.(Fileable); ok {
|
||||||
|
files := t.files()
|
||||||
|
|
||||||
|
// If we have files that need to be uploaded, we should delegate the
|
||||||
|
// request to UploadFile.
|
||||||
|
if hasFilesNeedingUpload(files) {
|
||||||
|
return bot.UploadFiles(t.method(), params, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
// However, if there are no files to be uploaded, there's likely things
|
||||||
|
// that need to be turned into params instead.
|
||||||
|
for _, file := range files {
|
||||||
|
params[file.Name] = file.Data.SendData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bot.MakeRequest(c.method(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send will send a Chattable item to Telegram and provides the
|
||||||
|
// returned Message.
|
||||||
|
func (bot *BotAPI) Send(c Chattable) (Message, error) {
|
||||||
|
resp, err := bot.Request(c)
|
||||||
|
if err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var message Message
|
||||||
|
err = json.Unmarshal(resp.Result, &message)
|
||||||
|
|
||||||
|
return message, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||||
|
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages []Message
|
||||||
|
err = json.Unmarshal(resp.Result, &messages)
|
||||||
|
|
||||||
|
return messages, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserProfilePhotos gets a user's profile photos.
|
||||||
|
//
|
||||||
|
// It requires UserID.
|
||||||
|
// Offset and Limit are optional.
|
||||||
|
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return UserProfilePhotos{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var profilePhotos UserProfilePhotos
|
||||||
|
err = json.Unmarshal(resp.Result, &profilePhotos)
|
||||||
|
|
||||||
|
return profilePhotos, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile returns a File which can download a file from Telegram.
|
||||||
|
//
|
||||||
|
// Requires FileID.
|
||||||
|
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return File{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var file File
|
||||||
|
err = json.Unmarshal(resp.Result, &file)
|
||||||
|
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUpdates fetches updates.
|
||||||
|
// If a WebHook is set, this will not return any data!
|
||||||
|
//
|
||||||
|
// Offset, Limit, Timeout, and AllowedUpdates are optional.
|
||||||
|
// To avoid stale items, set Offset to one higher than the previous item.
|
||||||
|
// Set Timeout to a large number to reduce requests, so you can get updates
|
||||||
|
// instantly instead of having to wait between requests.
|
||||||
|
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return []Update{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var updates []Update
|
||||||
|
err = json.Unmarshal(resp.Result, &updates)
|
||||||
|
|
||||||
|
return updates, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebhookInfo allows you to fetch information about a webhook and if
|
||||||
|
// one currently is set, along with pending update count and error messages.
|
||||||
|
func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
|
||||||
|
resp, err := bot.MakeRequest("getWebhookInfo", nil)
|
||||||
|
if err != nil {
|
||||||
|
return WebhookInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var info WebhookInfo
|
||||||
|
err = json.Unmarshal(resp.Result, &info)
|
||||||
|
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUpdatesChan starts and returns a channel for getting updates.
|
||||||
|
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
|
||||||
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-bot.shutdownChannel:
|
||||||
|
close(ch)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
updates, err := bot.GetUpdates(config)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
log.Println("Failed to get updates, retrying in 3 seconds...")
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, update := range updates {
|
||||||
|
if update.UpdateID >= config.Offset {
|
||||||
|
config.Offset = update.UpdateID + 1
|
||||||
|
ch <- update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
||||||
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
|
||||||
|
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
update, err := bot.HandleUpdate(r)
|
||||||
|
if err != nil {
|
||||||
|
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write(errMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- *update
|
||||||
|
})
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook.
|
||||||
|
func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel {
|
||||||
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
update, err := bot.HandleUpdate(r)
|
||||||
|
if err != nil {
|
||||||
|
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write(errMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- *update
|
||||||
|
close(ch)
|
||||||
|
}(w, r)
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleUpdate parses and returns update received via webhook
|
||||||
|
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
err := errors.New("wrong HTTP method required POST")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var update Update
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&update)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &update, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
|
||||||
|
//
|
||||||
|
// It doesn't support uploading files.
|
||||||
|
//
|
||||||
|
// See https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||||
|
// for details.
|
||||||
|
func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
|
||||||
|
params, err := c.params()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if t, ok := c.(Fileable); ok {
|
||||||
|
if hasFilesNeedingUpload(t.files()) {
|
||||||
|
return errors.New("unable to use http response to upload files")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values := buildParams(params)
|
||||||
|
values.Set("method", c.method())
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
_, err = w.Write([]byte(values.Encode()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChat gets information about a chat.
|
||||||
|
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return Chat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var chat Chat
|
||||||
|
err = json.Unmarshal(resp.Result, &chat)
|
||||||
|
|
||||||
|
return chat, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatAdministrators gets a list of administrators in the chat.
|
||||||
|
//
|
||||||
|
// If none have been appointed, only the creator will be returned.
|
||||||
|
// Bots are not shown, even if they are an administrator.
|
||||||
|
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return []ChatMember{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var members []ChatMember
|
||||||
|
err = json.Unmarshal(resp.Result, &members)
|
||||||
|
|
||||||
|
return members, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatMembersCount gets the number of users in a chat.
|
||||||
|
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = json.Unmarshal(resp.Result, &count)
|
||||||
|
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatMember gets a specific chat member.
|
||||||
|
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return ChatMember{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var member ChatMember
|
||||||
|
err = json.Unmarshal(resp.Result, &member)
|
||||||
|
|
||||||
|
return member, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGameHighScores allows you to get the high scores for a game.
|
||||||
|
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return []GameHighScore{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var highScores []GameHighScore
|
||||||
|
err = json.Unmarshal(resp.Result, &highScores)
|
||||||
|
|
||||||
|
return highScores, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInviteLink get InviteLink for a chat
|
||||||
|
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var inviteLink string
|
||||||
|
err = json.Unmarshal(resp.Result, &inviteLink)
|
||||||
|
|
||||||
|
return inviteLink, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStickerSet returns a StickerSet.
|
||||||
|
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return StickerSet{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var stickers StickerSet
|
||||||
|
err = json.Unmarshal(resp.Result, &stickers)
|
||||||
|
|
||||||
|
return stickers, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopPoll stops a poll and returns the result.
|
||||||
|
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return Poll{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var poll Poll
|
||||||
|
err = json.Unmarshal(resp.Result, &poll)
|
||||||
|
|
||||||
|
return poll, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMyCommands gets the currently registered commands.
|
||||||
|
func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
|
||||||
|
return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMyCommandsWithConfig gets the currently registered commands with a config.
|
||||||
|
func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) {
|
||||||
|
resp, err := bot.Request(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var commands []BotCommand
|
||||||
|
err = json.Unmarshal(resp.Result, &commands)
|
||||||
|
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyMessage copy messages of any kind. The method is analogous to the method
|
||||||
|
// forwardMessage, but the copied message doesn't have a link to the original
|
||||||
|
// message. Returns the MessageID of the sent message on success.
|
||||||
|
func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) {
|
||||||
|
params, err := config.params()
|
||||||
|
if err != nil {
|
||||||
|
return MessageID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := bot.MakeRequest(config.method(), params)
|
||||||
|
if err != nil {
|
||||||
|
return MessageID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageID MessageID
|
||||||
|
err = json.Unmarshal(resp.Result, &messageID)
|
||||||
|
|
||||||
|
return messageID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeText takes an input text and escape Telegram markup symbols.
|
||||||
|
// In this way we can send a text without being afraid of having to escape the characters manually.
|
||||||
|
// Note that you don't have to include the formatting style in the input text, or it will be escaped too.
|
||||||
|
// If there is an error, an empty string will be returned.
|
||||||
|
//
|
||||||
|
// parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML)
|
||||||
|
// text is the input string that will be escaped
|
||||||
|
func EscapeText(parseMode string, text string) string {
|
||||||
|
var replacer *strings.Replacer
|
||||||
|
|
||||||
|
if parseMode == ModeHTML {
|
||||||
|
replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&")
|
||||||
|
} else if parseMode == ModeMarkdown {
|
||||||
|
replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[")
|
||||||
|
} else if parseMode == ModeMarkdownV2 {
|
||||||
|
replacer = strings.NewReplacer(
|
||||||
|
"_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(",
|
||||||
|
"\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>",
|
||||||
|
"#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|",
|
||||||
|
"\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return replacer.Replace(text)
|
||||||
|
}
|
2468
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
generated
vendored
Normal file
2468
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -52,241 +52,117 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPhotoUpload creates a new photo uploader.
|
// NewCopyMessage creates a new copy message.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, fromChatID is the source chat,
|
||||||
|
// and messageID is the ID of the original message.
|
||||||
|
func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig {
|
||||||
|
return CopyMessageConfig{
|
||||||
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
|
FromChatID: fromChatID,
|
||||||
|
MessageID: messageID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPhoto creates a new sendPhoto request.
|
||||||
//
|
//
|
||||||
// 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,
|
||||||
// FileReader, or FileBytes.
|
// FileReader, or FileBytes.
|
||||||
//
|
//
|
||||||
// Note that you must send animated GIFs as a document.
|
// Note that you must send animated GIFs as a document.
|
||||||
func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig {
|
func NewPhoto(chatID int64, file RequestFileData) PhotoConfig {
|
||||||
return PhotoConfig{
|
return PhotoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPhotoShare shares an existing photo.
|
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||||
// You may use this to reshare an existing photo without reuploading it.
|
|
||||||
//
|
//
|
||||||
// chatID is where to send it, fileID is the ID of the file
|
// Note that you must send animated GIFs as a document.
|
||||||
// already uploaded.
|
func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig {
|
||||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
|
||||||
return PhotoConfig{
|
return PhotoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{
|
||||||
FileID: fileID,
|
ChannelUsername: username,
|
||||||
UseExisting: true,
|
},
|
||||||
|
File: file,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAudioUpload creates a new audio uploader.
|
// NewAudio creates a new sendAudio request.
|
||||||
//
|
func NewAudio(chatID int64, file RequestFileData) AudioConfig {
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewAudioUpload(chatID int64, file interface{}) AudioConfig {
|
|
||||||
return AudioConfig{
|
return AudioConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAudioShare shares an existing audio file.
|
// NewDocument creates a new sendDocument request.
|
||||||
// You may use this to reshare an existing audio file without
|
func NewDocument(chatID int64, file RequestFileData) DocumentConfig {
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the audio
|
|
||||||
// already uploaded.
|
|
||||||
func NewAudioShare(chatID int64, fileID string) AudioConfig {
|
|
||||||
return AudioConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDocumentUpload creates a new document uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewDocumentUpload(chatID int64, file interface{}) DocumentConfig {
|
|
||||||
return DocumentConfig{
|
return DocumentConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDocumentShare shares an existing document.
|
// NewSticker creates a new sendSticker request.
|
||||||
// You may use this to reshare an existing document without
|
func NewSticker(chatID int64, file RequestFileData) StickerConfig {
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the document
|
|
||||||
// already uploaded.
|
|
||||||
func NewDocumentShare(chatID int64, fileID string) DocumentConfig {
|
|
||||||
return DocumentConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStickerUpload creates a new sticker uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewStickerUpload(chatID int64, file interface{}) StickerConfig {
|
|
||||||
return StickerConfig{
|
return StickerConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStickerShare shares an existing sticker.
|
// NewVideo creates a new sendVideo request.
|
||||||
// You may use this to reshare an existing sticker without
|
func NewVideo(chatID int64, file RequestFileData) VideoConfig {
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the sticker
|
|
||||||
// already uploaded.
|
|
||||||
func NewStickerShare(chatID int64, fileID string) StickerConfig {
|
|
||||||
return StickerConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVideoUpload creates a new video uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewVideoUpload(chatID int64, file interface{}) VideoConfig {
|
|
||||||
return VideoConfig{
|
return VideoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVideoShare shares an existing video.
|
// NewAnimation creates a new sendAnimation request.
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
func NewAnimation(chatID int64, file RequestFileData) AnimationConfig {
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
|
||||||
return VideoConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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{
|
return AnimationConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAnimationShare shares an existing animation.
|
// NewVideoNote creates a new sendVideoNote request.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// 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,
|
||||||
// FileReader, or FileBytes.
|
// FileReader, or FileBytes.
|
||||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig {
|
||||||
return VideoNoteConfig{
|
return VideoNoteConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
Length: length,
|
Length: length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVideoNoteShare shares an existing video.
|
// NewVoice creates a new sendVoice request.
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
func NewVoice(chatID int64, file RequestFileData) VoiceConfig {
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig {
|
|
||||||
return VideoNoteConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
Length: length,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVoiceUpload creates a new voice uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewVoiceUpload(chatID int64, file interface{}) VoiceConfig {
|
|
||||||
return VoiceConfig{
|
return VoiceConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVoiceShare shares an existing voice.
|
|
||||||
// You may use this to reshare an existing voice without reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
|
||||||
return VoiceConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,26 +171,58 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
|||||||
// two to ten InputMediaPhoto or InputMediaVideo.
|
// two to ten InputMediaPhoto or InputMediaVideo.
|
||||||
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
||||||
return MediaGroupConfig{
|
return MediaGroupConfig{
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChatID: chatID,
|
ChatID: chatID,
|
||||||
},
|
Media: files,
|
||||||
InputMedia: files,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||||
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto {
|
||||||
return InputMediaPhoto{
|
return InputMediaPhoto{
|
||||||
|
BaseInputMedia{
|
||||||
Type: "photo",
|
Type: "photo",
|
||||||
Media: media,
|
Media: media,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaVideo creates a new InputMediaVideo.
|
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||||
func NewInputMediaVideo(media string) InputMediaVideo {
|
func NewInputMediaVideo(media RequestFileData) InputMediaVideo {
|
||||||
return InputMediaVideo{
|
return InputMediaVideo{
|
||||||
|
BaseInputMedia: BaseInputMedia{
|
||||||
Type: "video",
|
Type: "video",
|
||||||
Media: media,
|
Media: media,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||||
|
func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation {
|
||||||
|
return InputMediaAnimation{
|
||||||
|
BaseInputMedia: BaseInputMedia{
|
||||||
|
Type: "animation",
|
||||||
|
Media: media,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||||
|
func NewInputMediaAudio(media RequestFileData) InputMediaAudio {
|
||||||
|
return InputMediaAudio{
|
||||||
|
BaseInputMedia: BaseInputMedia{
|
||||||
|
Type: "audio",
|
||||||
|
Media: media,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInputMediaDocument creates a new InputMediaDocument.
|
||||||
|
func NewInputMediaDocument(media RequestFileData) InputMediaDocument {
|
||||||
|
return InputMediaDocument{
|
||||||
|
BaseInputMedia: BaseInputMedia{
|
||||||
|
Type: "document",
|
||||||
|
Media: media,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +277,7 @@ func NewChatAction(chatID int64, action string) ChatActionConfig {
|
|||||||
// NewUserProfilePhotos gets user profile photos.
|
// NewUserProfilePhotos gets user profile photos.
|
||||||
//
|
//
|
||||||
// userID is the ID of the user you wish to get profile photos from.
|
// userID is the ID of the user you wish to get profile photos from.
|
||||||
func NewUserProfilePhotos(userID int) UserProfilePhotosConfig {
|
func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig {
|
||||||
return UserProfilePhotosConfig{
|
return UserProfilePhotosConfig{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
@ -392,25 +300,33 @@ func NewUpdate(offset int) UpdateConfig {
|
|||||||
// NewWebhook creates a new webhook.
|
// NewWebhook creates a new webhook.
|
||||||
//
|
//
|
||||||
// link is the url parsable link you wish to get the updates.
|
// link is the url parsable link you wish to get the updates.
|
||||||
func NewWebhook(link string) WebhookConfig {
|
func NewWebhook(link string) (WebhookConfig, error) {
|
||||||
u, _ := url.Parse(link)
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return WebhookConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return WebhookConfig{
|
return WebhookConfig{
|
||||||
URL: u,
|
URL: u,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhookWithCert creates a new webhook with a certificate.
|
// NewWebhookWithCert creates a new webhook with a certificate.
|
||||||
//
|
//
|
||||||
// link is the url you wish to get webhooks,
|
// link is the url you wish to get webhooks,
|
||||||
// file contains a string to a file, FileReader, or FileBytes.
|
// file contains a string to a file, FileReader, or FileBytes.
|
||||||
func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
|
func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) {
|
||||||
u, _ := url.Parse(link)
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return WebhookConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return WebhookConfig{
|
return WebhookConfig{
|
||||||
URL: u,
|
URL: u,
|
||||||
Certificate: file,
|
Certificate: file,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultArticle creates a new inline query article.
|
// NewInlineQueryResultArticle creates a new inline query article.
|
||||||
@ -438,6 +354,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
|
||||||
|
func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle {
|
||||||
|
return InlineQueryResultArticle{
|
||||||
|
Type: "article",
|
||||||
|
ID: id,
|
||||||
|
Title: title,
|
||||||
|
InputMessageContent: InputTextMessageContent{
|
||||||
|
Text: messageText,
|
||||||
|
ParseMode: "MarkdownV2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
||||||
return InlineQueryResultArticle{
|
return InlineQueryResultArticle{
|
||||||
@ -465,7 +394,7 @@ func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF
|
|||||||
return InlineQueryResultCachedGIF{
|
return InlineQueryResultCachedGIF{
|
||||||
Type: "gif",
|
Type: "gif",
|
||||||
ID: id,
|
ID: id,
|
||||||
GifID: gifID,
|
GIFID: gifID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,12 +407,12 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
|
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
|
||||||
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif {
|
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
|
||||||
return InlineQueryResultCachedMpeg4Gif{
|
return InlineQueryResultCachedMPEG4GIF{
|
||||||
Type: "mpeg4_gif",
|
Type: "mpeg4_gif",
|
||||||
ID: id,
|
ID: id,
|
||||||
MGifID: MPEG4GifID,
|
MPEG4FileID: MPEG4GIFID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,6 +463,16 @@ func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
|
||||||
|
func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker {
|
||||||
|
return InlineQueryResultCachedSticker{
|
||||||
|
Type: "sticker",
|
||||||
|
ID: id,
|
||||||
|
StickerID: stickerID,
|
||||||
|
Title: title,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultAudio creates a new inline query audio.
|
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
||||||
return InlineQueryResultAudio{
|
return InlineQueryResultAudio{
|
||||||
@ -628,6 +567,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message.
|
||||||
|
func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig {
|
||||||
|
return EditMessageTextConfig{
|
||||||
|
BaseEdit: BaseEdit{
|
||||||
|
ChatID: chatID,
|
||||||
|
MessageID: messageID,
|
||||||
|
ReplyMarkup: &replyMarkup,
|
||||||
|
},
|
||||||
|
Text: text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewEditMessageCaption allows you to edit the caption of a message.
|
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
||||||
return EditMessageCaptionConfig{
|
return EditMessageCaptionConfig{
|
||||||
@ -651,17 +602,6 @@ func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHideKeyboard hides the keyboard, with the option for being selective
|
|
||||||
// or hiding for everyone.
|
|
||||||
func NewHideKeyboard(selective bool) ReplyKeyboardHide {
|
|
||||||
log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard")
|
|
||||||
|
|
||||||
return ReplyKeyboardHide{
|
|
||||||
HideKeyboard: true,
|
|
||||||
Selective: selective,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
||||||
// or hiding for everyone.
|
// or hiding for everyone.
|
||||||
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
||||||
@ -717,6 +657,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOneTimeReplyKeyboard creates a new one time keyboard.
|
||||||
|
func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||||
|
markup := NewReplyKeyboard(rows...)
|
||||||
|
markup.OneTimeKeyboard = true
|
||||||
|
return markup
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||||
// and data for a callback.
|
// and data for a callback.
|
||||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||||
@ -726,6 +673,15 @@ func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text
|
||||||
|
// which goes to a LoginURL.
|
||||||
|
func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton {
|
||||||
|
return InlineKeyboardButton{
|
||||||
|
Text: text,
|
||||||
|
LoginURL: &loginURL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineKeyboardButtonURL creates an inline keyboard button with text
|
// NewInlineKeyboardButtonURL creates an inline keyboard button with text
|
||||||
// which goes to a URL.
|
// which goes to a URL.
|
||||||
func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton {
|
func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton {
|
||||||
@ -784,7 +740,7 @@ func NewCallbackWithAlert(id, text string) CallbackConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewInvoice creates a new Invoice request to the user.
|
// NewInvoice creates a new Invoice request to the user.
|
||||||
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig {
|
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig {
|
||||||
return InvoiceConfig{
|
return InvoiceConfig{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
Title: title,
|
Title: title,
|
||||||
@ -796,33 +752,176 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP
|
|||||||
Prices: prices}
|
Prices: prices}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSetChatPhotoUpload creates a new chat photo uploader.
|
// NewChatTitle allows you to update the title of a chat.
|
||||||
//
|
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
||||||
// chatID is where to send it, file is a string path to the file,
|
return SetChatTitleConfig{
|
||||||
// FileReader, or FileBytes.
|
ChatID: chatID,
|
||||||
//
|
Title: title,
|
||||||
// Note that you must send animated GIFs as a document.
|
}
|
||||||
func NewSetChatPhotoUpload(chatID int64, file interface{}) SetChatPhotoConfig {
|
}
|
||||||
|
|
||||||
|
// NewChatDescription allows you to update the description of a chat.
|
||||||
|
func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig {
|
||||||
|
return SetChatDescriptionConfig{
|
||||||
|
ChatID: chatID,
|
||||||
|
Description: description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChatPhoto allows you to update the photo for a chat.
|
||||||
|
func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig {
|
||||||
return SetChatPhotoConfig{
|
return SetChatPhotoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{
|
||||||
File: file,
|
ChatID: chatID,
|
||||||
UseExisting: false,
|
},
|
||||||
|
File: photo,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSetChatPhotoShare shares an existing photo.
|
// NewDeleteChatPhoto allows you to delete the photo for a chat.
|
||||||
// You may use this to reshare an existing photo without reuploading it.
|
func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig {
|
||||||
//
|
return DeleteChatPhotoConfig{
|
||||||
// chatID is where to send it, fileID is the ID of the file
|
ChatID: chatID,
|
||||||
// already uploaded.
|
}
|
||||||
func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig {
|
}
|
||||||
return SetChatPhotoConfig{
|
|
||||||
BaseFile: BaseFile{
|
// NewPoll allows you to create a new poll.
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
func NewPoll(chatID int64, question string, options ...string) SendPollConfig {
|
||||||
FileID: fileID,
|
return SendPollConfig{
|
||||||
UseExisting: true,
|
BaseChat: BaseChat{
|
||||||
|
ChatID: chatID,
|
||||||
|
},
|
||||||
|
Question: question,
|
||||||
|
Options: options,
|
||||||
|
IsAnonymous: true, // This is Telegram's default.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStopPoll allows you to stop a poll.
|
||||||
|
func NewStopPoll(chatID int64, messageID int) StopPollConfig {
|
||||||
|
return StopPollConfig{
|
||||||
|
BaseEdit{
|
||||||
|
ChatID: chatID,
|
||||||
|
MessageID: messageID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDice allows you to send a random dice roll.
|
||||||
|
func NewDice(chatID int64) DiceConfig {
|
||||||
|
return DiceConfig{
|
||||||
|
BaseChat: BaseChat{
|
||||||
|
ChatID: chatID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiceWithEmoji allows you to send a random roll of one of many types.
|
||||||
|
//
|
||||||
|
// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5).
|
||||||
|
func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
|
||||||
|
return DiceConfig{
|
||||||
|
BaseChat: BaseChat{
|
||||||
|
ChatID: chatID,
|
||||||
|
},
|
||||||
|
Emoji: emoji,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeDefault represents the default scope of bot commands.
|
||||||
|
func NewBotCommandScopeDefault() BotCommandScope {
|
||||||
|
return BotCommandScope{Type: "default"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
|
||||||
|
// covering all private chats.
|
||||||
|
func NewBotCommandScopeAllPrivateChats() BotCommandScope {
|
||||||
|
return BotCommandScope{Type: "all_private_chats"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
|
||||||
|
// covering all group and supergroup chats.
|
||||||
|
func NewBotCommandScopeAllGroupChats() BotCommandScope {
|
||||||
|
return BotCommandScope{Type: "all_group_chats"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
|
||||||
|
// covering all group and supergroup chat administrators.
|
||||||
|
func NewBotCommandScopeAllChatAdministrators() BotCommandScope {
|
||||||
|
return BotCommandScope{Type: "all_chat_administrators"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeChat represents the scope of bot commands, covering a
|
||||||
|
// specific chat.
|
||||||
|
func NewBotCommandScopeChat(chatID int64) BotCommandScope {
|
||||||
|
return BotCommandScope{
|
||||||
|
Type: "chat",
|
||||||
|
ChatID: chatID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
|
||||||
|
// covering all administrators of a specific group or supergroup chat.
|
||||||
|
func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope {
|
||||||
|
return BotCommandScope{
|
||||||
|
Type: "chat_administrators",
|
||||||
|
ChatID: chatID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
|
||||||
|
// specific member of a group or supergroup chat.
|
||||||
|
func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope {
|
||||||
|
return BotCommandScope{
|
||||||
|
Type: "chat_member",
|
||||||
|
ChatID: chatID,
|
||||||
|
UserID: userID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetMyCommandsWithScope allows you to set the registered commands for a
|
||||||
|
// given scope.
|
||||||
|
func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig {
|
||||||
|
return GetMyCommandsConfig{Scope: &scope}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
|
||||||
|
// commands for a given scope and language code.
|
||||||
|
func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig {
|
||||||
|
return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSetMyCommands allows you to set the registered commands.
|
||||||
|
func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
|
||||||
|
return SetMyCommandsConfig{Commands: commands}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
|
||||||
|
func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig {
|
||||||
|
return SetMyCommandsConfig{Commands: commands, Scope: &scope}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
|
||||||
|
// and language code.
|
||||||
|
func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig {
|
||||||
|
return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteMyCommands allows you to delete the registered commands.
|
||||||
|
func NewDeleteMyCommands() DeleteMyCommandsConfig {
|
||||||
|
return DeleteMyCommandsConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
|
||||||
|
// scope.
|
||||||
|
func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig {
|
||||||
|
return DeleteMyCommandsConfig{Scope: &scope}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
|
||||||
|
// scope and language code.
|
||||||
|
func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig {
|
||||||
|
return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
|
||||||
|
}
|
97
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
generated
vendored
Normal file
97
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package tgbotapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Params represents a set of parameters that gets passed to a request.
|
||||||
|
type Params map[string]string
|
||||||
|
|
||||||
|
// AddNonEmpty adds a value if it not an empty string.
|
||||||
|
func (p Params) AddNonEmpty(key, value string) {
|
||||||
|
if value != "" {
|
||||||
|
p[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNonZero adds a value if it is not zero.
|
||||||
|
func (p Params) AddNonZero(key string, value int) {
|
||||||
|
if value != 0 {
|
||||||
|
p[key] = strconv.Itoa(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNonZero64 is the same as AddNonZero except uses an int64.
|
||||||
|
func (p Params) AddNonZero64(key string, value int64) {
|
||||||
|
if value != 0 {
|
||||||
|
p[key] = strconv.FormatInt(value, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddBool adds a value of a bool if it is true.
|
||||||
|
func (p Params) AddBool(key string, value bool) {
|
||||||
|
if value {
|
||||||
|
p[key] = strconv.FormatBool(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNonZeroFloat adds a floating point value that is not zero.
|
||||||
|
func (p Params) AddNonZeroFloat(key string, value float64) {
|
||||||
|
if value != 0 {
|
||||||
|
p[key] = strconv.FormatFloat(value, 'f', 6, 64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterface adds an interface if it is not nil and can be JSON marshalled.
|
||||||
|
func (p Params) AddInterface(key string, value interface{}) error {
|
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p[key] = string(b)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFirstValid attempts to add the first item that is not a default value.
|
||||||
|
//
|
||||||
|
// For example, AddFirstValid(0, "", "test") would add "test".
|
||||||
|
func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
||||||
|
for _, arg := range args {
|
||||||
|
switch v := arg.(type) {
|
||||||
|
case int:
|
||||||
|
if v != 0 {
|
||||||
|
p[key] = strconv.Itoa(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if v != 0 {
|
||||||
|
p[key] = strconv.FormatInt(v, 10)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if v != "" {
|
||||||
|
p[key] = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
b, err := json.Marshal(arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p[key] = string(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -54,13 +54,15 @@ type (
|
|||||||
Credentials *EncryptedCredentials `json:"credentials"`
|
Credentials *EncryptedCredentials `json:"credentials"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PassportFile represents a file uploaded to Telegram Passport. Currently all
|
// PassportFile represents a file uploaded to Telegram Passport. Currently, all
|
||||||
// Telegram Passport files are in JPEG format when decrypted and don't exceed
|
// Telegram Passport files are in JPEG format when decrypted and don't exceed
|
||||||
// 10MB.
|
// 10MB.
|
||||||
PassportFile struct {
|
PassportFile struct {
|
||||||
// Unique identifier for this file
|
// Unique identifier for this file
|
||||||
FileID string `json:"file_id"`
|
FileID string `json:"file_id"`
|
||||||
|
|
||||||
|
FileUniqueID string `json:"file_unique_id"`
|
||||||
|
|
||||||
// File size
|
// File size
|
||||||
FileSize int `json:"file_size"`
|
FileSize int `json:"file_size"`
|
||||||
|
|
||||||
@ -212,7 +214,7 @@ type (
|
|||||||
// PassportElementErrorFile represents an issue with a document scan. The
|
// PassportElementErrorFile represents an issue with a document scan. The
|
||||||
// error is considered resolved when the file with the document scan changes.
|
// error is considered resolved when the file with the document scan changes.
|
||||||
PassportElementErrorFile struct {
|
PassportElementErrorFile struct {
|
||||||
// Error source, must be file
|
// Error source, must be a file
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
|
|
||||||
// The section of the user's Telegram Passport which has the issue, one
|
// The section of the user's Telegram Passport which has the issue, one
|
3225
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
generated
vendored
Normal file
3225
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
vendor/github.com/technoweenie/multipartstreamer/LICENSE
generated
vendored
7
vendor/github.com/technoweenie/multipartstreamer/LICENSE
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
Copyright (c) 2013-* rick olson
|
|
||||||
|
|
||||||
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.
|
|
47
vendor/github.com/technoweenie/multipartstreamer/README.md
generated
vendored
47
vendor/github.com/technoweenie/multipartstreamer/README.md
generated
vendored
@ -1,47 +0,0 @@
|
|||||||
# multipartstreamer
|
|
||||||
|
|
||||||
Package multipartstreamer helps you encode large files in MIME multipart format
|
|
||||||
without reading the entire content into memory. It uses io.MultiReader to
|
|
||||||
combine an inner multipart.Reader with a file handle.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/technoweenie/multipartstreamer.go"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
ms := multipartstreamer.New()
|
|
||||||
|
|
||||||
ms.WriteFields(map[string]string{
|
|
||||||
"key": "some-key",
|
|
||||||
"AWSAccessKeyId": "ABCDEF",
|
|
||||||
"acl": "some-acl",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Add any io.Reader to the multipart.Reader.
|
|
||||||
ms.WriteReader("file", "filename", some_ioReader, size)
|
|
||||||
|
|
||||||
// Shortcut for adding local file.
|
|
||||||
ms.WriteFile("file", "path/to/file")
|
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", "someurl", nil)
|
|
||||||
ms.SetupRequest(req)
|
|
||||||
|
|
||||||
res, _ := http.DefaultClient.Do(req)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
One limitation: You can only write a single file.
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
* Multiple files?
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Heavily inspired by James
|
|
||||||
|
|
||||||
https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/Zjg5l4nKcQ0
|
|
101
vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go
generated
vendored
101
vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go
generated
vendored
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
Package multipartstreamer helps you encode large files in MIME multipart format
|
|
||||||
without reading the entire content into memory. It uses io.MultiReader to
|
|
||||||
combine an inner multipart.Reader with a file handle.
|
|
||||||
*/
|
|
||||||
package multipartstreamer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime/multipart"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MultipartStreamer struct {
|
|
||||||
ContentType string
|
|
||||||
bodyBuffer *bytes.Buffer
|
|
||||||
bodyWriter *multipart.Writer
|
|
||||||
closeBuffer *bytes.Buffer
|
|
||||||
reader io.Reader
|
|
||||||
contentLength int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// New initializes a new MultipartStreamer.
|
|
||||||
func New() (m *MultipartStreamer) {
|
|
||||||
m = &MultipartStreamer{bodyBuffer: new(bytes.Buffer)}
|
|
||||||
|
|
||||||
m.bodyWriter = multipart.NewWriter(m.bodyBuffer)
|
|
||||||
boundary := m.bodyWriter.Boundary()
|
|
||||||
m.ContentType = "multipart/form-data; boundary=" + boundary
|
|
||||||
|
|
||||||
closeBoundary := fmt.Sprintf("\r\n--%s--\r\n", boundary)
|
|
||||||
m.closeBuffer = bytes.NewBufferString(closeBoundary)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteFields writes multiple form fields to the multipart.Writer.
|
|
||||||
func (m *MultipartStreamer) WriteFields(fields map[string]string) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
for key, value := range fields {
|
|
||||||
err = m.bodyWriter.WriteField(key, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteReader adds an io.Reader to get the content of a file. The reader is
|
|
||||||
// not accessed until the multipart.Reader is copied to some output writer.
|
|
||||||
func (m *MultipartStreamer) WriteReader(key, filename string, size int64, reader io.Reader) (err error) {
|
|
||||||
m.reader = reader
|
|
||||||
m.contentLength = size
|
|
||||||
|
|
||||||
_, err = m.bodyWriter.CreateFormFile(key, filename)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteFile is a shortcut for adding a local file as an io.Reader.
|
|
||||||
func (m *MultipartStreamer) WriteFile(key, filename string) error {
|
|
||||||
fh, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stat, err := fh.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.WriteReader(key, filepath.Base(filename), stat.Size(), fh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupRequest sets up the http.Request body, and some crucial HTTP headers.
|
|
||||||
func (m *MultipartStreamer) SetupRequest(req *http.Request) {
|
|
||||||
req.Body = m.GetReader()
|
|
||||||
req.Header.Add("Content-Type", m.ContentType)
|
|
||||||
req.ContentLength = m.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MultipartStreamer) Boundary() string {
|
|
||||||
return m.bodyWriter.Boundary()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len calculates the byte size of the multipart content.
|
|
||||||
func (m *MultipartStreamer) Len() int64 {
|
|
||||||
return m.contentLength + int64(m.bodyBuffer.Len()) + int64(m.closeBuffer.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReader gets an io.ReadCloser for passing to an http.Request.
|
|
||||||
func (m *MultipartStreamer) GetReader() io.ReadCloser {
|
|
||||||
reader := io.MultiReader(m.bodyBuffer, m.reader, m.closeBuffer)
|
|
||||||
return ioutil.NopCloser(reader)
|
|
||||||
}
|
|
9
vendor/modules.txt
vendored
9
vendor/modules.txt
vendored
@ -76,9 +76,9 @@ github.com/fsnotify/fsnotify
|
|||||||
# github.com/go-asn1-ber/asn1-ber v1.5.3
|
# github.com/go-asn1-ber/asn1-ber v1.5.3
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/go-asn1-ber/asn1-ber
|
github.com/go-asn1-ber/asn1-ber
|
||||||
# github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
|
# github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0
|
||||||
## explicit; go 1.12
|
## explicit; go 1.16
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api
|
github.com/go-telegram-bot-api/telegram-bot-api/v5
|
||||||
# github.com/golang-jwt/jwt v3.2.2+incompatible
|
# github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
## explicit
|
## explicit
|
||||||
github.com/golang-jwt/jwt
|
github.com/golang-jwt/jwt
|
||||||
@ -384,9 +384,6 @@ github.com/stretchr/testify/suite
|
|||||||
# github.com/subosito/gotenv v1.2.0
|
# github.com/subosito/gotenv v1.2.0
|
||||||
## explicit
|
## explicit
|
||||||
github.com/subosito/gotenv
|
github.com/subosito/gotenv
|
||||||
# github.com/technoweenie/multipartstreamer v1.0.1
|
|
||||||
## explicit
|
|
||||||
github.com/technoweenie/multipartstreamer
|
|
||||||
# github.com/tinylib/msgp v1.1.6
|
# github.com/tinylib/msgp v1.1.6
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/tinylib/msgp/msgp
|
github.com/tinylib/msgp/msgp
|
||||||
|
Loading…
Reference in New Issue
Block a user