Add support for uploading multiple files.
parent
2f7211a708
commit
ce4fc988c9
262
bot.go
262
bot.go
|
@ -9,13 +9,12 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/technoweenie/multipartstreamer"
|
||||
)
|
||||
|
||||
// BotAPI allows you to interact with the Telegram Bot API.
|
||||
|
@ -82,7 +81,7 @@ func buildParams(in Params) (out url.Values) {
|
|||
}
|
||||
|
||||
// MakeRequest makes a request to a specific endpoint with our token.
|
||||
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, error) {
|
||||
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) {
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, params: %v\n", endpoint, params)
|
||||
}
|
||||
|
@ -93,14 +92,14 @@ func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, err
|
|||
|
||||
resp, err := bot.Client.PostForm(method, values)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return apiResp, err
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
|
@ -114,14 +113,14 @@ func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, err
|
|||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return apiResp, Error{
|
||||
return &apiResp, &Error{
|
||||
Code: apiResp.ErrorCode,
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return apiResp, nil
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
||||
|
@ -148,86 +147,102 @@ func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse)
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// UploadFile makes a request to the API with a file.
|
||||
//
|
||||
// Requires the parameter to hold the file not be in the params.
|
||||
// File should be a string to a file path, a FileBytes struct,
|
||||
// a FileReader struct, or a url.URL.
|
||||
//
|
||||
// Note that if your FileReader has a size set to -1, it will read
|
||||
// the file into memory to calculate a size.
|
||||
func (bot *BotAPI) UploadFile(endpoint string, params Params, fieldname string, file interface{}) (APIResponse, error) {
|
||||
ms := multipartstreamer.New()
|
||||
// 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)
|
||||
|
||||
switch f := file.(type) {
|
||||
// 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 {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
switch f := file.File.(type) {
|
||||
case string:
|
||||
ms.WriteFields(params)
|
||||
|
||||
fileHandle, err := os.Open(f)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
panic(err)
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
fi, err := os.Stat(f)
|
||||
part, err := m.CreateFormFile(file.Name, fileHandle.Name())
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
|
||||
io.Copy(part, fileHandle)
|
||||
case FileBytes:
|
||||
ms.WriteFields(params)
|
||||
part, err := m.CreateFormFile(file.Name, f.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(f.Bytes)
|
||||
ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
|
||||
io.Copy(part, buf)
|
||||
case FileReader:
|
||||
ms.WriteFields(params)
|
||||
|
||||
if f.Size != -1 {
|
||||
ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
|
||||
|
||||
break
|
||||
part, err := m.CreateFormFile(file.Name, f.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if f.Size != -1 {
|
||||
io.Copy(part, f.Reader)
|
||||
} else {
|
||||
data, err := ioutil.ReadAll(f.Reader)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
|
||||
ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
|
||||
case url.URL:
|
||||
params[fieldname] = f.String()
|
||||
|
||||
ms.WriteFields(params)
|
||||
default:
|
||||
return APIResponse{}, errors.New(ErrBadFileType)
|
||||
io.Copy(part, buf)
|
||||
}
|
||||
case FileURL:
|
||||
val := string(f)
|
||||
if err := m.WriteField(file.Name, val); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
case FileID:
|
||||
val := string(f)
|
||||
if err := m.WriteField(file.Name, val); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
default:
|
||||
panic(errors.New(ErrBadFileType))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, fieldname: %s, params: %v, file: %T\n", endpoint, fieldname, params, file)
|
||||
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, nil)
|
||||
req, err := http.NewRequest("POST", method, r)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ms.SetupRequest(req)
|
||||
req.Header.Set("Content-Type", m.FormDataContentType())
|
||||
|
||||
resp, err := bot.Client.Do(req)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return apiResp, err
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
|
@ -241,13 +256,13 @@ func (bot *BotAPI) UploadFile(endpoint string, params Params, fieldname string,
|
|||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return apiResp, Error{
|
||||
return &apiResp, &Error{
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return apiResp, nil
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// GetFileDirectURL returns direct URL to file
|
||||
|
@ -287,23 +302,54 @@ func (bot *BotAPI) IsMessageToMe(message Message) bool {
|
|||
return strings.Contains(message.Text, "@"+bot.Self.UserName)
|
||||
}
|
||||
|
||||
func hasFilesNeedingUpload(files []RequestFile) bool {
|
||||
for _, file := range files {
|
||||
switch file.File.(type) {
|
||||
case string, FileBytes, FileReader:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Request sends a Chattable to Telegram, and returns the APIResponse.
|
||||
func (bot *BotAPI) Request(c Chattable) (APIResponse, error) {
|
||||
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) {
|
||||
params, err := c.params()
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch t := c.(type) {
|
||||
case Fileable:
|
||||
if t.useExistingFile() {
|
||||
return bot.MakeRequest(t.method(), params)
|
||||
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)
|
||||
}
|
||||
|
||||
return bot.UploadFile(t.method(), params, t.name(), t.getFile())
|
||||
// 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 {
|
||||
var s string
|
||||
|
||||
switch f := file.File.(type) {
|
||||
case string:
|
||||
s = f
|
||||
case FileID:
|
||||
s = string(f)
|
||||
case FileURL:
|
||||
s = string(f)
|
||||
default:
|
||||
return bot.MakeRequest(c.method(), params)
|
||||
return nil, errors.New(ErrBadFileType)
|
||||
}
|
||||
|
||||
params[file.Name] = s
|
||||
}
|
||||
}
|
||||
|
||||
return bot.MakeRequest(c.method(), params)
|
||||
}
|
||||
|
||||
// Send will send a Chattable item to Telegram and provides the
|
||||
|
@ -322,9 +368,51 @@ func (bot *BotAPI) Send(c Chattable) (Message, error) {
|
|||
|
||||
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||
params, _ := config.params()
|
||||
filesToUpload := []RequestFile{}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
newMedia := []interface{}{}
|
||||
|
||||
for idx, media := range config.Media {
|
||||
switch m := media.(type) {
|
||||
case InputMediaPhoto:
|
||||
switch f := m.Media.(type) {
|
||||
case string, FileBytes, FileReader:
|
||||
m.Media = fmt.Sprintf("attach://file-%d", idx)
|
||||
newMedia = append(newMedia, m)
|
||||
|
||||
filesToUpload = append(filesToUpload, RequestFile{
|
||||
Name: fmt.Sprintf("file-%d", idx),
|
||||
File: f,
|
||||
})
|
||||
default:
|
||||
newMedia = append(newMedia, m)
|
||||
}
|
||||
case InputMediaVideo:
|
||||
switch f := m.Media.(type) {
|
||||
case string, FileBytes, FileReader:
|
||||
m.Media = fmt.Sprintf("attach://file-%d", idx)
|
||||
newMedia = append(newMedia, m)
|
||||
|
||||
filesToUpload = append(filesToUpload, RequestFile{
|
||||
Name: fmt.Sprintf("file-%d", idx),
|
||||
File: f,
|
||||
})
|
||||
default:
|
||||
newMedia = append(newMedia, m)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New(ErrBadFileType)
|
||||
}
|
||||
}
|
||||
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.AddInterface("media", newMedia)
|
||||
|
||||
resp, err := bot.UploadFiles(config.method(), params, filesToUpload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -340,9 +428,7 @@ func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
|||
// It requires UserID.
|
||||
// Offset and Limit are optional.
|
||||
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return UserProfilePhotos{}, err
|
||||
}
|
||||
|
@ -357,9 +443,7 @@ func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
|
|||
//
|
||||
// Requires FileID.
|
||||
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
|
@ -378,9 +462,7 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
|||
// 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) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []Update{}, err
|
||||
}
|
||||
|
@ -481,7 +563,7 @@ func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
|
|||
}
|
||||
|
||||
if t, ok := c.(Fileable); ok {
|
||||
if !t.useExistingFile() {
|
||||
if hasFilesNeedingUpload(t.files()) {
|
||||
return errors.New("unable to use http response to upload files")
|
||||
}
|
||||
}
|
||||
|
@ -496,9 +578,7 @@ func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
|
|||
|
||||
// GetChat gets information about a chat.
|
||||
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Chat{}, err
|
||||
}
|
||||
|
@ -514,9 +594,7 @@ func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
|||
// 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) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []ChatMember{}, err
|
||||
}
|
||||
|
@ -529,9 +607,7 @@ func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]Cha
|
|||
|
||||
// GetChatMembersCount gets the number of users in a chat.
|
||||
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
@ -544,9 +620,7 @@ func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error
|
|||
|
||||
// GetChatMember gets a specific chat member.
|
||||
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return ChatMember{}, err
|
||||
}
|
||||
|
@ -559,9 +633,7 @@ func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error)
|
|||
|
||||
// GetGameHighScores allows you to get the high scores for a game.
|
||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []GameHighScore{}, err
|
||||
}
|
||||
|
@ -574,9 +646,7 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh
|
|||
|
||||
// GetInviteLink get InviteLink for a chat
|
||||
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -589,9 +659,7 @@ func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
|||
|
||||
// GetStickerSet returns a StickerSet.
|
||||
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return StickerSet{}, err
|
||||
}
|
||||
|
@ -604,12 +672,7 @@ func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error)
|
|||
|
||||
// StopPoll stops a poll and returns the result.
|
||||
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return Poll{}, err
|
||||
}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Poll{}, err
|
||||
}
|
||||
|
@ -624,12 +687,7 @@ func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
|||
func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
|
||||
config := GetMyCommandsConfig{}
|
||||
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
68
bot_test.go
68
bot_test.go
|
@ -92,7 +92,7 @@ func TestSendWithMessageForward(t *testing.T) {
|
|||
func TestSendWithNewPhoto(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -107,7 +107,7 @@ func TestSendWithNewPhotoWithFileBytes(t *testing.T) {
|
|||
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||
b := FileBytes{Name: "image.jpg", Bytes: data}
|
||||
|
||||
msg := NewPhotoUpload(ChatID, b)
|
||||
msg := NewPhoto(ChatID, b)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -122,7 +122,7 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
|
|||
f, _ := os.Open("tests/image.jpg")
|
||||
reader := FileReader{Name: "image.jpg", Reader: f, Size: -1}
|
||||
|
||||
msg := NewPhotoUpload(ChatID, reader)
|
||||
msg := NewPhoto(ChatID, reader)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -134,7 +134,7 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
|
|||
func TestSendWithNewPhotoReply(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||
msg.ReplyToMessageID = ReplyToMessageID
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
@ -147,7 +147,7 @@ func TestSendWithNewPhotoReply(t *testing.T) {
|
|||
func TestSendNewPhotoToChannel(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoUploadToChannel(Channel, "tests/image.jpg")
|
||||
msg := NewPhotoToChannel(Channel, "tests/image.jpg")
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -163,7 +163,7 @@ func TestSendNewPhotoToChannelFileBytes(t *testing.T) {
|
|||
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||
b := FileBytes{Name: "image.jpg", Bytes: data}
|
||||
|
||||
msg := NewPhotoUploadToChannel(Channel, b)
|
||||
msg := NewPhotoToChannel(Channel, b)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -179,7 +179,7 @@ func TestSendNewPhotoToChannelFileReader(t *testing.T) {
|
|||
f, _ := os.Open("tests/image.jpg")
|
||||
reader := FileReader{Name: "image.jpg", Reader: f, Size: -1}
|
||||
|
||||
msg := NewPhotoUploadToChannel(Channel, reader)
|
||||
msg := NewPhotoToChannel(Channel, reader)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -192,7 +192,7 @@ func TestSendNewPhotoToChannelFileReader(t *testing.T) {
|
|||
func TestSendWithExistingPhoto(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoShare(ChatID, ExistingPhotoFileID)
|
||||
msg := NewPhoto(ChatID, FileID(ExistingPhotoFileID))
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -204,7 +204,19 @@ func TestSendWithExistingPhoto(t *testing.T) {
|
|||
func TestSendWithNewDocument(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocumentUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewDocument(ChatID, "tests/image.jpg")
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewDocumentAndThumb(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocument(ChatID, "tests/voice.ogg")
|
||||
msg.AddFile("thumb", "tests/image.jpg")
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
|
@ -215,7 +227,7 @@ func TestSendWithNewDocument(t *testing.T) {
|
|||
func TestSendWithExistingDocument(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocumentShare(ChatID, ExistingDocumentFileID)
|
||||
msg := NewDocument(ChatID, FileID(ExistingDocumentFileID))
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
|
@ -226,7 +238,7 @@ func TestSendWithExistingDocument(t *testing.T) {
|
|||
func TestSendWithNewAudio(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewAudioUpload(ChatID, "tests/audio.mp3")
|
||||
msg := NewAudio(ChatID, "tests/audio.mp3")
|
||||
msg.Title = "TEST"
|
||||
msg.Duration = 10
|
||||
msg.Performer = "TEST"
|
||||
|
@ -242,7 +254,7 @@ func TestSendWithNewAudio(t *testing.T) {
|
|||
func TestSendWithExistingAudio(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewAudioShare(ChatID, ExistingAudioFileID)
|
||||
msg := NewAudio(ChatID, FileID(ExistingAudioFileID))
|
||||
msg.Title = "TEST"
|
||||
msg.Duration = 10
|
||||
msg.Performer = "TEST"
|
||||
|
@ -257,7 +269,7 @@ func TestSendWithExistingAudio(t *testing.T) {
|
|||
func TestSendWithNewVoice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVoiceUpload(ChatID, "tests/voice.ogg")
|
||||
msg := NewVoice(ChatID, "tests/voice.ogg")
|
||||
msg.Duration = 10
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -269,7 +281,7 @@ func TestSendWithNewVoice(t *testing.T) {
|
|||
func TestSendWithExistingVoice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVoiceShare(ChatID, ExistingVoiceFileID)
|
||||
msg := NewVoice(ChatID, FileID(ExistingVoiceFileID))
|
||||
msg.Duration = 10
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -311,7 +323,7 @@ func TestSendWithVenue(t *testing.T) {
|
|||
func TestSendWithNewVideo(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoUpload(ChatID, "tests/video.mp4")
|
||||
msg := NewVideo(ChatID, "tests/video.mp4")
|
||||
msg.Duration = 10
|
||||
msg.Caption = "TEST"
|
||||
|
||||
|
@ -325,7 +337,7 @@ func TestSendWithNewVideo(t *testing.T) {
|
|||
func TestSendWithExistingVideo(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoShare(ChatID, ExistingVideoFileID)
|
||||
msg := NewVideo(ChatID, FileID(ExistingVideoFileID))
|
||||
msg.Duration = 10
|
||||
msg.Caption = "TEST"
|
||||
|
||||
|
@ -339,7 +351,7 @@ func TestSendWithExistingVideo(t *testing.T) {
|
|||
func TestSendWithNewVideoNote(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoNoteUpload(ChatID, 240, "tests/videonote.mp4")
|
||||
msg := NewVideoNote(ChatID, 240, "tests/videonote.mp4")
|
||||
msg.Duration = 10
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
@ -352,7 +364,7 @@ func TestSendWithNewVideoNote(t *testing.T) {
|
|||
func TestSendWithExistingVideoNote(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoNoteShare(ChatID, 240, ExistingVideoNoteFileID)
|
||||
msg := NewVideoNote(ChatID, 240, FileID(ExistingVideoNoteFileID))
|
||||
msg.Duration = 10
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
@ -365,7 +377,7 @@ func TestSendWithExistingVideoNote(t *testing.T) {
|
|||
func TestSendWithNewSticker(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -377,7 +389,7 @@ func TestSendWithNewSticker(t *testing.T) {
|
|||
func TestSendWithExistingSticker(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
||||
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -389,7 +401,7 @@ func TestSendWithExistingSticker(t *testing.T) {
|
|||
func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||
RemoveKeyboard: true,
|
||||
Selective: false,
|
||||
|
@ -404,7 +416,7 @@ func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
|||
func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
||||
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||
RemoveKeyboard: true,
|
||||
Selective: false,
|
||||
|
@ -526,9 +538,9 @@ func TestSendWithMediaGroup(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
cfg := NewMediaGroup(ChatID, []interface{}{
|
||||
NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
|
||||
NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
|
||||
NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
|
||||
NewInputMediaPhoto(FileURL("https://i.imgur.com/unQLJIb.jpg")),
|
||||
NewInputMediaPhoto("tests/image.jpg"),
|
||||
NewInputMediaVideo("tests/video.mp4"),
|
||||
})
|
||||
|
||||
messages, err := bot.SendMediaGroup(cfg)
|
||||
|
@ -537,11 +549,11 @@ func TestSendWithMediaGroup(t *testing.T) {
|
|||
}
|
||||
|
||||
if messages == nil {
|
||||
t.Error()
|
||||
t.Error("No received messages")
|
||||
}
|
||||
|
||||
if len(messages) != 3 {
|
||||
t.Error()
|
||||
if len(messages) != len(cfg.Media) {
|
||||
t.Errorf("Different number of messages: %d", len(messages))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
178
configs.go
178
configs.go
|
@ -55,12 +55,19 @@ type Chattable interface {
|
|||
method() string
|
||||
}
|
||||
|
||||
// RequestFile represents a file associated with a request. May involve
|
||||
// uploading a file, or passing an existing ID.
|
||||
type RequestFile struct {
|
||||
// The multipart upload field name.
|
||||
Name string
|
||||
// The file to upload.
|
||||
File interface{}
|
||||
}
|
||||
|
||||
// Fileable is any config type that can be sent that includes a file.
|
||||
type Fileable interface {
|
||||
Chattable
|
||||
name() string
|
||||
getFile() interface{}
|
||||
useExistingFile() bool
|
||||
files() []RequestFile
|
||||
}
|
||||
|
||||
// BaseChat is base type for all chat config types.
|
||||
|
@ -87,13 +94,23 @@ func (chat *BaseChat) params() (Params, error) {
|
|||
// BaseFile is a base type for all file config types.
|
||||
type BaseFile struct {
|
||||
BaseChat
|
||||
File interface{}
|
||||
FileID string
|
||||
UseExisting bool
|
||||
Files []RequestFile
|
||||
MimeType string
|
||||
FileSize int
|
||||
}
|
||||
|
||||
// AddFile specifies a file for a Telegram request.
|
||||
func (file *BaseFile) AddFile(name string, f interface{}) {
|
||||
if file.Files == nil {
|
||||
file.Files = make([]RequestFile, 0, 1)
|
||||
}
|
||||
|
||||
file.Files = append(file.Files, RequestFile{
|
||||
Name: name,
|
||||
File: f,
|
||||
})
|
||||
}
|
||||
|
||||
func (file BaseFile) params() (Params, error) {
|
||||
params, err := file.BaseChat.params()
|
||||
|
||||
|
@ -103,12 +120,8 @@ func (file BaseFile) params() (Params, error) {
|
|||
return params, err
|
||||
}
|
||||
|
||||
func (file BaseFile) getFile() interface{} {
|
||||
return file.File
|
||||
}
|
||||
|
||||
func (file BaseFile) useExistingFile() bool {
|
||||
return file.UseExisting
|
||||
func (file BaseFile) files() []RequestFile {
|
||||
return file.Files
|
||||
}
|
||||
|
||||
// BaseEdit is base type of all chat edits.
|
||||
|
@ -194,7 +207,6 @@ type PhotoConfig struct {
|
|||
func (config PhotoConfig) params() (Params, error) {
|
||||
params, err := config.BaseFile.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonEmpty("caption", config.Caption)
|
||||
params.AddNonEmpty("parse_mode", config.ParseMode)
|
||||
|
||||
|
@ -225,7 +237,6 @@ func (config AudioConfig) params() (Params, error) {
|
|||
return params, err
|
||||
}
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonZero("duration", config.Duration)
|
||||
params.AddNonEmpty("performer", config.Performer)
|
||||
params.AddNonEmpty("title", config.Title)
|
||||
|
@ -253,7 +264,6 @@ type DocumentConfig struct {
|
|||
func (config DocumentConfig) params() (Params, error) {
|
||||
params, err := config.BaseFile.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonEmpty("caption", config.Caption)
|
||||
params.AddNonEmpty("parse_mode", config.ParseMode)
|
||||
|
||||
|
@ -274,11 +284,7 @@ type StickerConfig struct {
|
|||
}
|
||||
|
||||
func (config StickerConfig) params() (Params, error) {
|
||||
params, err := config.BaseChat.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
|
||||
return params, err
|
||||
return config.BaseChat.params()
|
||||
}
|
||||
|
||||
func (config StickerConfig) name() string {
|
||||
|
@ -301,7 +307,6 @@ type VideoConfig struct {
|
|||
func (config VideoConfig) params() (Params, error) {
|
||||
params, err := config.BaseChat.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonZero("duration", config.Duration)
|
||||
params.AddNonEmpty("caption", config.Caption)
|
||||
params.AddNonEmpty("parse_mode", config.ParseMode)
|
||||
|
@ -329,7 +334,6 @@ type AnimationConfig struct {
|
|||
func (config AnimationConfig) params() (Params, error) {
|
||||
params, err := config.BaseChat.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonZero("duration", config.Duration)
|
||||
params.AddNonEmpty("caption", config.Caption)
|
||||
params.AddNonEmpty("parse_mode", config.ParseMode)
|
||||
|
@ -355,7 +359,6 @@ type VideoNoteConfig struct {
|
|||
func (config VideoNoteConfig) params() (Params, error) {
|
||||
params, err := config.BaseChat.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonZero("duration", config.Duration)
|
||||
params.AddNonZero("length", config.Length)
|
||||
|
||||
|
@ -381,7 +384,6 @@ type VoiceConfig struct {
|
|||
func (config VoiceConfig) params() (Params, error) {
|
||||
params, err := config.BaseChat.params()
|
||||
|
||||
params.AddNonEmpty(config.name(), config.FileID)
|
||||
params.AddNonZero("duration", config.Duration)
|
||||
params.AddNonEmpty("caption", config.Caption)
|
||||
params.AddNonEmpty("parse_mode", config.ParseMode)
|
||||
|
@ -683,23 +685,28 @@ func (config EditMessageCaptionConfig) method() string {
|
|||
return "editMessageCaption"
|
||||
}
|
||||
|
||||
// EditMessageMediaConfig contains information about editing a message's media.
|
||||
// EditMessageMediaConfig allows you to make an editMessageMedia request.
|
||||
type EditMessageMediaConfig struct {
|
||||
BaseEdit
|
||||
|
||||
Media interface{}
|
||||
}
|
||||
|
||||
func (config EditMessageMediaConfig) files() []RequestFile {
|
||||
return []RequestFile{
|
||||
{
|
||||
Name: "media",
|
||||
File: config.Media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (EditMessageMediaConfig) method() string {
|
||||
return "editMessageMedia"
|
||||
}
|
||||
|
||||
func (config EditMessageMediaConfig) params() (Params, error) {
|
||||
params, err := config.BaseEdit.params()
|
||||
|
||||
params.AddInterface("media", config.Media)
|
||||
|
||||
return params, err
|
||||
return config.BaseEdit.params()
|
||||
}
|
||||
|
||||
// EditMessageReplyMarkupConfig allows you to modify the reply markup
|
||||
|
@ -818,14 +825,6 @@ func (config WebhookConfig) name() string {
|
|||
return "certificate"
|
||||
}
|
||||
|
||||
func (config WebhookConfig) getFile() interface{} {
|
||||
return config.Certificate
|
||||
}
|
||||
|
||||
func (config WebhookConfig) useExistingFile() bool {
|
||||
return config.URL != nil
|
||||
}
|
||||
|
||||
// RemoveWebhookConfig is a helper to remove a webhook.
|
||||
type RemoveWebhookConfig struct {
|
||||
}
|
||||
|
@ -854,6 +853,12 @@ type FileReader struct {
|
|||
Size int64
|
||||
}
|
||||
|
||||
// FileURL is a URL to use as a file for a request.
|
||||
type FileURL string
|
||||
|
||||
// FileID is an ID of a file already uploaded to Telegram.
|
||||
type FileID string
|
||||
|
||||
// InlineConfig contains information on making an InlineQuery response.
|
||||
type InlineConfig struct {
|
||||
InlineQueryID string `json:"inline_query_id"`
|
||||
|
@ -1312,14 +1317,6 @@ func (config SetChatPhotoConfig) name() string {
|
|||
return "photo"
|
||||
}
|
||||
|
||||
func (config SetChatPhotoConfig) getFile() interface{} {
|
||||
return config.File
|
||||
}
|
||||
|
||||
func (config SetChatPhotoConfig) useExistingFile() bool {
|
||||
return config.UseExisting
|
||||
}
|
||||
|
||||
// DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo.
|
||||
type DeleteChatPhotoConfig struct {
|
||||
ChatID int64
|
||||
|
@ -1415,18 +1412,13 @@ func (config UploadStickerConfig) params() (Params, error) {
|
|||
return params, nil
|
||||
}
|
||||
|
||||
func (config UploadStickerConfig) name() string {
|
||||
return "png_sticker"
|
||||
func (config UploadStickerConfig) files() []RequestFile {
|
||||
return []RequestFile{
|
||||
{
|
||||
Name: "png_sticker",
|
||||
File: config.PNGSticker,
|
||||
},
|
||||
}
|
||||
|
||||
func (config UploadStickerConfig) getFile() interface{} {
|
||||
return config.PNGSticker
|
||||
}
|
||||
|
||||
func (config UploadStickerConfig) useExistingFile() bool {
|
||||
_, ok := config.PNGSticker.(string)
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// NewStickerSetConfig allows creating a new sticker set.
|
||||
|
@ -1454,12 +1446,6 @@ func (config NewStickerSetConfig) params() (Params, error) {
|
|||
params["name"] = config.Name
|
||||
params["title"] = config.Title
|
||||
|
||||
if sticker, ok := config.PNGSticker.(string); ok {
|
||||
params[config.name()] = sticker
|
||||
} else if sticker, ok := config.TGSSticker.(string); ok {
|
||||
params[config.name()] = sticker
|
||||
}
|
||||
|
||||
params["emojis"] = config.Emojis
|
||||
|
||||
params.AddBool("contains_masks", config.ContainsMasks)
|
||||
|
@ -1469,26 +1455,18 @@ func (config NewStickerSetConfig) params() (Params, error) {
|
|||
return params, err
|
||||
}
|
||||
|
||||
func (config NewStickerSetConfig) getFile() interface{} {
|
||||
return config.PNGSticker
|
||||
}
|
||||
|
||||
func (config NewStickerSetConfig) name() string {
|
||||
return "png_sticker"
|
||||
}
|
||||
|
||||
func (config NewStickerSetConfig) useExistingFile() bool {
|
||||
func (config NewStickerSetConfig) files() []RequestFile {
|
||||
if config.PNGSticker != nil {
|
||||
_, ok := config.PNGSticker.(string)
|
||||
return ok
|
||||
return []RequestFile{{
|
||||
Name: "png_sticker",
|
||||
File: config.PNGSticker,
|
||||
}}
|
||||
}
|
||||
|
||||
if config.TGSSticker != nil {
|
||||
_, ok := config.TGSSticker.(string)
|
||||
return ok
|
||||
}
|
||||
|
||||
panic("NewStickerSetConfig had nil PNGSticker and TGSSticker")
|
||||
return []RequestFile{{
|
||||
Name: "tgs_sticker",
|
||||
File: config.TGSSticker,
|
||||
}}
|
||||
}
|
||||
|
||||
// AddStickerConfig allows you to add a sticker to a set.
|
||||
|
@ -1512,29 +1490,24 @@ func (config AddStickerConfig) params() (Params, error) {
|
|||
params["name"] = config.Name
|
||||
params["emojis"] = config.Emojis
|
||||
|
||||
if sticker, ok := config.PNGSticker.(string); ok {
|
||||
params[config.name()] = sticker
|
||||
} else if sticker, ok := config.TGSSticker.(string); ok {
|
||||
params[config.name()] = sticker
|
||||
}
|
||||
|
||||
err := params.AddInterface("mask_position", config.MaskPosition)
|
||||
|
||||
return params, err
|
||||
}
|
||||
|
||||
func (config AddStickerConfig) name() string {
|
||||
return "png_sticker"
|
||||
func (config AddStickerConfig) files() []RequestFile {
|
||||
if config.PNGSticker != nil {
|
||||
return []RequestFile{{
|
||||
Name: "png_sticker",
|
||||
File: config.PNGSticker,
|
||||
}}
|
||||
}
|
||||
|
||||
func (config AddStickerConfig) getFile() interface{} {
|
||||
return config.PNGSticker
|
||||
}
|
||||
return []RequestFile{{
|
||||
Name: "tgs_sticker",
|
||||
File: config.TGSSticker,
|
||||
}}
|
||||
|
||||
func (config AddStickerConfig) useExistingFile() bool {
|
||||
_, ok := config.PNGSticker.(string)
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// SetStickerPositionConfig allows you to change the position of a sticker in a set.
|
||||
|
@ -1601,15 +1574,6 @@ func (config SetStickerSetThumbConfig) name() string {
|
|||
return "thumb"
|
||||
}
|
||||
|
||||
func (config SetStickerSetThumbConfig) getFile() interface{} {
|
||||
return config.Thumb
|
||||
}
|
||||
|
||||
func (config SetStickerSetThumbConfig) useExistingFile() bool {
|
||||
_, ok := config.Thumb.(string)
|
||||
return ok
|
||||
}
|
||||
|
||||
// SetChatStickerSetConfig allows you to set the sticker set for a supergroup.
|
||||
type SetChatStickerSetConfig struct {
|
||||
ChatID int64
|
||||
|
@ -1652,6 +1616,9 @@ func (config DeleteChatStickerSetConfig) params() (Params, error) {
|
|||
// MediaGroupConfig allows you to send a group of media.
|
||||
//
|
||||
// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo).
|
||||
//
|
||||
// Due to additional processing required, this config is not Chattable or
|
||||
// Fileable. It must be uploaded with SendMediaGroup.
|
||||
type MediaGroupConfig struct {
|
||||
ChatID int64
|
||||
ChannelUsername string
|
||||
|
@ -1669,9 +1636,6 @@ func (config MediaGroupConfig) params() (Params, error) {
|
|||
params := make(Params)
|
||||
|
||||
params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
|
||||
if err := params.AddInterface("media", config.Media); err != nil {
|
||||
return params, nil
|
||||
}
|
||||
params.AddBool("disable_notification", config.DisableNotification)
|
||||
params.AddNonZero("reply_to_message_id", config.ReplyToMessageID)
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,5 +1,3 @@
|
|||
module github.com/go-telegram-bot-api/telegram-bot-api/v5
|
||||
|
||||
require github.com/technoweenie/multipartstreamer v1.0.1
|
||||
|
||||
go 1.13
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,2 +0,0 @@
|
|||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
346
helpers.go
346
helpers.go
|
@ -51,261 +51,131 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// NewPhotoUpload creates a new photo uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
// NewPhoto creates a new sendPhoto request.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
func NewPhoto(chatID int64, file interface{}) PhotoConfig {
|
||||
config := PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewPhotoUploadToChannel creates a new photo uploader to send a photo to a channel.
|
||||
//
|
||||
// username is the username of the channel, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoUploadToChannel(username string, file interface{}) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
func NewPhotoToChannel(username string, file interface{}) PhotoConfig {
|
||||
config := PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{
|
||||
ChannelUsername: username,
|
||||
},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewPhotoShare shares an existing photo.
|
||||
// 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
|
||||
// already uploaded.
|
||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
// NewAudio creates a new sendAudio request.
|
||||
func NewAudio(chatID int64, file interface{}) AudioConfig {
|
||||
config := AudioConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewAudioUpload creates a new audio uploader.
|
||||
// NewDocument creates a new sendDocument request.
|
||||
func NewDocument(chatID int64, file interface{}) DocumentConfig {
|
||||
config := DocumentConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewSticker creates a new sendSticker request.
|
||||
func NewSticker(chatID int64, file interface{}) StickerConfig {
|
||||
config := StickerConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewVideo creates a new sendVideo request.
|
||||
func NewVideo(chatID int64, file interface{}) VideoConfig {
|
||||
config := VideoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewAnimation creates a new sendAnimation request.
|
||||
func NewAnimation(chatID int64, file interface{}) AnimationConfig {
|
||||
config := AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewVideoNote creates a new sendVideoNote request.
|
||||
//
|
||||
// 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{
|
||||
func NewVideoNote(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||
config := VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAudioShare shares an existing audio file.
|
||||
// You may use this to reshare an existing audio file without
|
||||
// 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{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentShare shares an existing document.
|
||||
// You may use this to reshare an existing document without
|
||||
// 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{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStickerShare shares an existing sticker.
|
||||
// You may use this to reshare an existing sticker without
|
||||
// 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{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// 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{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnimationShare shares an existing animation.
|
||||
// You may use this to reshare an existing animation without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the animation
|
||||
// already uploaded.
|
||||
func NewAnimationShare(chatID int64, fileID string) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoNoteUpload creates a new video note uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||
return VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
Length: length,
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewVideoNoteShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// 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{
|
||||
// NewVoice creates a new sendVoice request.
|
||||
func NewVoice(chatID int64, file interface{}) VoiceConfig {
|
||||
config := VoiceConfig{
|
||||
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{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
config.AddFile(config.name(), file)
|
||||
|
||||
// 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,
|
||||
},
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// NewMediaGroup creates a new media group. Files should be an array of
|
||||
|
@ -318,7 +188,7 @@ func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
|||
}
|
||||
|
||||
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
||||
func NewInputMediaPhoto(media interface{}) InputMediaPhoto {
|
||||
return InputMediaPhoto{
|
||||
BaseInputMedia{
|
||||
Type: "photo",
|
||||
|
@ -328,7 +198,7 @@ func NewInputMediaPhoto(media string) InputMediaPhoto {
|
|||
}
|
||||
|
||||
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||
func NewInputMediaVideo(media string) InputMediaVideo {
|
||||
func NewInputMediaVideo(media interface{}) InputMediaVideo {
|
||||
return InputMediaVideo{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "video",
|
||||
|
@ -338,7 +208,7 @@ func NewInputMediaVideo(media string) InputMediaVideo {
|
|||
}
|
||||
|
||||
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||
func NewInputMediaAnimation(media string) InputMediaAnimation {
|
||||
func NewInputMediaAnimation(media interface{}) InputMediaAnimation {
|
||||
return InputMediaAnimation{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "animation",
|
||||
|
@ -348,7 +218,7 @@ func NewInputMediaAnimation(media string) InputMediaAnimation {
|
|||
}
|
||||
|
||||
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||
func NewInputMediaAudio(media string) InputMediaAudio {
|
||||
func NewInputMediaAudio(media interface{}) InputMediaAudio {
|
||||
return InputMediaAudio{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "audio",
|
||||
|
@ -875,37 +745,6 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP
|
|||
Prices: prices}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoUpload creates a new chat photo uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewSetChatPhotoUpload(chatID int64, file interface{}) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoShare shares an existing photo.
|
||||
// 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
|
||||
// already uploaded.
|
||||
func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewChatTitle allows you to update the title of a chat.
|
||||
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
||||
return SetChatTitleConfig{
|
||||
|
@ -924,14 +763,17 @@ func NewChatDescription(chatID int64, description string) SetChatDescriptionConf
|
|||
|
||||
// NewChatPhoto allows you to update the photo for a chat.
|
||||
func NewChatPhoto(chatID int64, photo interface{}) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
config := SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
File: photo,
|
||||
},
|
||||
}
|
||||
|
||||
config.AddFile(config.name(), photo)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// NewDeleteChatPhoto allows you to delete the photo for a chat.
|
||||
|
|
14
types.go
14
types.go
|
@ -1113,9 +1113,9 @@ type BotCommand struct {
|
|||
// BaseInputMedia is a base type for the InputMedia types.
|
||||
type BaseInputMedia struct {
|
||||
Type string `json:"type"`
|
||||
Media string `json:"media"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
Media interface{} `json:"media"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
}
|
||||
|
||||
// InputMediaPhoto is a photo to send as part of a media group.
|
||||
|
@ -1126,10 +1126,10 @@ type InputMediaPhoto struct {
|
|||
// InputMediaVideo is a video to send as part of a media group.
|
||||
type InputMediaVideo struct {
|
||||
BaseInputMedia
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Duration int `json:"duration"`
|
||||
SupportsStreaming bool `json:"supports_streaming"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
SupportsStreaming bool `json:"supports_streaming,omitempty"`
|
||||
}
|
||||
|
||||
// InputMediaAnimation is an animation to send as part of a media group.
|
||||
|
|
|
@ -331,3 +331,21 @@ var (
|
|||
_ Chattable = VoiceConfig{}
|
||||
_ Chattable = WebhookConfig{}
|
||||
)
|
||||
|
||||
// Ensure all Fileable types are correct.
|
||||
var (
|
||||
_ Fileable = (*PhotoConfig)(nil)
|
||||
_ Fileable = (*AudioConfig)(nil)
|
||||
_ Fileable = (*DocumentConfig)(nil)
|
||||
_ Fileable = (*StickerConfig)(nil)
|
||||
_ Fileable = (*VideoConfig)(nil)
|
||||
_ Fileable = (*AnimationConfig)(nil)
|
||||
_ Fileable = (*VideoNoteConfig)(nil)
|
||||
_ Fileable = (*VoiceConfig)(nil)
|
||||
_ Fileable = (*SetChatPhotoConfig)(nil)
|
||||
_ Fileable = (*EditMessageMediaConfig)(nil)
|
||||
_ Fileable = (*SetChatPhotoConfig)(nil)
|
||||
_ Fileable = (*UploadStickerConfig)(nil)
|
||||
_ Fileable = (*NewStickerSetConfig)(nil)
|
||||
_ Fileable = (*AddStickerConfig)(nil)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue