diff --git a/helpers.go b/helpers.go index f489a52..d21230a 100644 --- a/helpers.go +++ b/helpers.go @@ -153,6 +153,31 @@ func NewVideoShare(chatID int, fileID string) VideoConfig { } } +// NewVoiceUpload creates a new voice uploader. +// This requires a file on the local filesystem to upload to Telegram. +// Perhaps set a ChatAction of ChatRecordVideo or ChatUploadVideo while processing. +// +// chatID is where to send it, filename is the path to the file. +func NewVoiceUpload(chatID int, filename string) VoiceConfig { + return VoiceConfig{ + ChatID: chatID, + UseExistingVoice: false, + FilePath: filename, + } +} + +// 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 int, fileID string) VoiceConfig { + return VoiceConfig{ + ChatID: chatID, + UseExistingVoice: true, + FileID: fileID, + } +} + // NewLocation shares your location. // Perhaps set a ChatAction of ChatFindLocation while processing. // diff --git a/methods.go b/methods.go index 7b25dc3..298b27e 100644 --- a/methods.go +++ b/methods.go @@ -70,6 +70,8 @@ type PhotoConfig struct { type AudioConfig struct { ChatID int Duration int + Performer string + Title string ReplyToMessageID int ReplyMarkup interface{} UseExistingAudio bool @@ -109,6 +111,17 @@ type VideoConfig struct { FileID string } +// VoiceConfig contains information about a SendVoice request. +type VoiceConfig struct { + ChatID int + Duration int + ReplyToMessageID int + ReplyMarkup interface{} + UseExistingVoice bool + FilePath string + FileID string +} + // LocationConfig contains information about a SendLocation request. type LocationConfig struct { ChatID int @@ -390,7 +403,11 @@ func (bot *BotAPI) SendPhoto(config PhotoConfig) (Message, error) { } // SendAudio sends or uploads an audio clip to a chat. -// If using a file, the file must be encoded as an .ogg with OPUS. +// If using a file, the file must be in the .mp3 format. +// +// when the fields title and performer are both empty +// and the mime-type of the file to be sent is not audio/mpeg, +// the file must be in an .ogg file encoded with OPUS. // // Requires ChatID and FileID OR FilePath. // ReplyToMessageID and ReplyMarkup are optional. @@ -413,6 +430,12 @@ func (bot *BotAPI) SendAudio(config AudioConfig) (Message, error) { v.Add("reply_markup", string(data)) } + if config.Performer != "" { + v.Add("performer", config.Performer) + } + if config.Title != "" { + v.Add("title", config.Title) + } resp, err := bot.MakeRequest("sendAudio", v) if err != nil { @@ -436,6 +459,9 @@ func (bot *BotAPI) SendAudio(config AudioConfig) (Message, error) { if config.ReplyToMessageID != 0 { params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID) } + if config.Duration != 0 { + params["duration"] = strconv.Itoa(config.Duration) + } if config.ReplyMarkup != nil { data, err := json.Marshal(config.ReplyMarkup) if err != nil { @@ -444,6 +470,12 @@ func (bot *BotAPI) SendAudio(config AudioConfig) (Message, error) { params["reply_markup"] = string(data) } + if config.Performer != "" { + params["performer"] = config.Performer + } + if config.Title != "" { + params["title"] = config.Title + } resp, err := bot.UploadFile("sendAudio", params, "audio", config.FilePath) if err != nil { @@ -527,6 +559,80 @@ func (bot *BotAPI) SendDocument(config DocumentConfig) (Message, error) { return message, nil } +// SendVoice sends or uploads a playable voice to a chat. +// If using a file, the file must be encoded as an .ogg with OPUS. +// +// Requires ChatID and FileID OR FilePath. +// ReplyToMessageID and ReplyMarkup are optional. +func (bot *BotAPI) SendVoice(config VoiceConfig) (Message, error) { + if config.UseExistingVoice { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatID)) + v.Add("voice", config.FileID) + if config.ReplyToMessageID != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID)) + } + if config.Duration != 0 { + v.Add("duration", strconv.Itoa(config.Duration)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendVoice", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("SendVoice req : %+v\n", v) + log.Printf("SendVoice resp: %+v\n", message) + } + + return message, nil + } + + params := make(map[string]string) + + params["chat_id"] = strconv.Itoa(config.ChatID) + if config.ReplyToMessageID != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID) + } + if config.Duration != 0 { + params["duration"] = strconv.Itoa(config.Duration) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("SendVoice", params, "voice", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("SendVoice resp: %+v\n", message) + } + + return message, nil +} + // SendSticker sends or uploads a sticker to a chat. // // Requires ChatID and FileID OR FilePath. diff --git a/types.go b/types.go index fda3298..2cbe72d 100644 --- a/types.go +++ b/types.go @@ -73,6 +73,7 @@ type Message struct { Photo []PhotoSize `json:"photo"` Sticker Sticker `json:"sticker"` Video Video `json:"video"` + Voice Voice `json:"voice"` Caption string `json:"caption"` Contact Contact `json:"contact"` Location Location `json:"location"` @@ -102,12 +103,15 @@ type PhotoSize struct { FileSize int `json:"file_size"` } -// Audio contains information about audio, including ID and Duration. +// Audio contains information about audio, +// including ID, Duration, Performer and Title. type Audio struct { - FileID string `json:"file_id"` - Duration int `json:"duration"` - MimeType string `json:"mime_type"` - FileSize int `json:"file_size"` + FileID string `json:"file_id"` + Duration int `json:"duration"` + Performer string `json:"performer"` + Title string `json:"title"` + MimeType string `json:"mime_type"` + FileSize int `json:"file_size"` } // Document contains information about a document, including ID and a Thumbnail. @@ -139,6 +143,14 @@ type Video struct { FileSize int `json:"file_size"` } +// Voice contains information about a voice, including ID and duration. +type Voice struct { + FileID string `json:"file_id"` + Duration int `json:"duration"` + MimeType string `json:"mime_type"` + FileSize int `json:"file_size"` +} + // Contact contains information about a contact, such as PhoneNumber and UserId. type Contact struct { PhoneNumber string `json:"phone_number"`