MarkdownV2 as default, use MarkdownLegacy for old-fashioned MD.

pull/270/head
Ian Patrick Badtrousers 5 years ago
parent 16baf678a5
commit 12299becfa

281
bot.go

@ -149,6 +149,11 @@ var (
cbackRx = regexp.MustCompile(`^\f(\w+)(\|(.+))?$`) cbackRx = regexp.MustCompile(`^\f(\w+)(\|(.+))?$`)
) )
func (b *Bot) handleCommand(m *Message, cmdName, cmdBot string) bool {
return false
}
// Start brings bot into motion by consuming incoming // Start brings bot into motion by consuming incoming
// updates (see Bot.Updates channel). // updates (see Bot.Updates channel).
func (b *Bot) Start() { func (b *Bot) Start() {
@ -277,7 +282,7 @@ func (b *Bot) incomingUpdate(upd *Update) {
defer b.deferDebug() defer b.deferDebug()
} }
handler(from, to) handler(from, to)
}(b, handler, m.Chat.ID, m.MigrateTo) }(b, handler, m.MigrateFrom, m.MigrateTo)
} else { } else {
panic("telebot: migration handler is bad") panic("telebot: migration handler is bad")
@ -307,13 +312,8 @@ func (b *Bot) incomingUpdate(upd *Update) {
if upd.Callback != nil { if upd.Callback != nil {
if upd.Callback.Data != "" { if upd.Callback.Data != "" {
if upd.Callback.MessageID != "" {
upd.Callback.Message = &Message{
InlineID: upd.Callback.MessageID,
}
}
data := upd.Callback.Data data := upd.Callback.Data
if data[0] == '\f' { if data[0] == '\f' {
match := cbackRx.FindAllStringSubmatch(data, -1) match := cbackRx.FindAllStringSubmatch(data, -1)
@ -503,7 +503,7 @@ func (b *Bot) Stop() {
// some Sendable (or string!) and optional send options. // some Sendable (or string!) and optional send options.
// //
// Note: since most arguments are of type interface{}, but have pointer // Note: since most arguments are of type interface{}, but have pointer
// method receivers, make sure to pass them by-pointer, NOT by-value. // method recievers, make sure to pass them by-pointer, NOT by-value.
// //
// What is a send option exactly? It can be one of the following types: // What is a send option exactly? It can be one of the following types:
// //
@ -540,15 +540,14 @@ func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Messag
f := x.MediaFile() f := x.MediaFile()
switch { if f.InCloud() {
case f.InCloud():
mediaRepr = f.FileID mediaRepr = f.FileID
case f.FileURL != "": } else if f.FileURL != "" {
mediaRepr = f.FileURL mediaRepr = f.FileURL
case f.OnDisk() || f.FileReader != nil: } else if f.OnDisk() || f.FileReader != nil {
mediaRepr = "attach://" + strconv.Itoa(i) mediaRepr = fmt.Sprintf("attach://%d", i)
files[strconv.Itoa(i)] = *f files[strconv.Itoa(i)] = *f
default: } else {
return nil, errors.Errorf( return nil, errors.Errorf(
"telebot: album entry #%d doesn't exist anywhere", i) "telebot: album entry #%d doesn't exist anywhere", i)
} }
@ -556,15 +555,13 @@ func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Messag
switch y := x.(type) { switch y := x.(type) {
case *Photo: case *Photo:
jsonRepr, _ = json.Marshal(struct { jsonRepr, _ = json.Marshal(struct {
Type string `json:"type"` Type string `json:"type"`
Media string `json:"media"` Caption string `json:"caption"`
Caption string `json:"caption,omitempty"` Media string `json:"media"`
ParseMode ParseMode `json:"parse_mode,omitempty"`
}{ }{
"photo", "photo",
mediaRepr,
y.Caption, y.Caption,
y.ParseMode, mediaRepr,
}) })
case *Video: case *Video:
jsonRepr, _ = json.Marshal(struct { jsonRepr, _ = json.Marshal(struct {
@ -619,7 +616,7 @@ func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Messag
return nil, errors.Errorf("api error: %s", resp.Description) return nil, errors.Errorf("api error: %s", resp.Description)
} }
for attachName := range files { for attachName, _ := range files {
i, _ := strconv.Atoi(attachName) i, _ := strconv.Atoi(attachName)
var newID string var newID string
@ -714,39 +711,11 @@ func (b *Bot) Edit(message Editable, what interface{}, options ...interface{}) (
return extractMsgResponse(respJSON) return extractMsgResponse(respJSON)
} }
// EditReplyMarkup used to edit reply markup of already sent message. // EditCaption used to edit already sent photo caption with known recepient and message id.
//
// On success, returns edited message object
func (b *Bot) EditReplyMarkup(message Editable, markup *ReplyMarkup) (*Message, error) {
messageID, chatID := message.MessageSig()
params := map[string]string{}
// if inline message
if chatID == 0 {
params["inline_message_id"] = messageID
} else {
params["chat_id"] = strconv.FormatInt(chatID, 10)
params["message_id"] = messageID
}
processButtons(markup.InlineKeyboard)
jsonMarkup, _ := json.Marshal(markup)
params["reply_markup"] = string(jsonMarkup)
respJSON, err := b.Raw("editMessageReplyMarkup", params)
if err != nil {
return nil, err
}
return extractMsgResponse(respJSON)
}
// EditCaption used to edit already sent photo caption with known recipient and message id.
// //
// On success, returns edited message object // On success, returns edited message object
func (b *Bot) EditCaption(message Editable, caption string, options ...interface{}) (*Message, error) { func (b *Bot) EditCaption(originalMsg Editable, caption string) (*Message, error) {
messageID, chatID := message.MessageSig() messageID, chatID := originalMsg.MessageSig()
params := map[string]string{"caption": caption} params := map[string]string{"caption": caption}
@ -758,9 +727,6 @@ func (b *Bot) EditCaption(message Editable, caption string, options ...interface
params["message_id"] = messageID params["message_id"] = messageID
} }
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
respJSON, err := b.Raw("editMessageCaption", params) respJSON, err := b.Raw("editMessageCaption", params)
if err != nil { if err != nil {
return nil, err return nil, err
@ -769,7 +735,7 @@ func (b *Bot) EditCaption(message Editable, caption string, options ...interface
return extractMsgResponse(respJSON) return extractMsgResponse(respJSON)
} }
// EditMedia used to edit already sent media with known recipient and message id. // EditMedia used to edit already sent media with known recepient and message id.
// //
// Use cases: // Use cases:
// //
@ -784,34 +750,28 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
file := make(map[string]File) file := make(map[string]File)
f := inputMedia.MediaFile() f := inputMedia.MediaFile()
thumbAttachName := "thumb"
switch { if f.InCloud() {
case f.InCloud():
mediaRepr = f.FileID mediaRepr = f.FileID
case f.FileURL != "": } else if f.FileURL != "" {
mediaRepr = f.FileURL mediaRepr = f.FileURL
case f.OnDisk() || f.FileReader != nil: } else if f.OnDisk() || f.FileReader != nil {
s := f.FileLocal s := f.FileLocal
if f.FileReader != nil { if f.FileReader != nil {
s = "0" s = "0"
} }
if s == thumbAttachName {
thumbAttachName = "thumb2"
}
mediaRepr = "attach://" + s mediaRepr = "attach://" + s
file[s] = *f file[s] = *f
default: } else {
return nil, errors.Errorf( return nil, errors.Errorf(
"telebot: can't edit media, it doesn't exist anywhere") "telebot: can't edit media, it doesn't exist anywhere")
} }
type FileJSON struct { type FileJson struct {
// All types. // All types.
Type string `json:"type"` Type string `json:"type"`
Caption string `json:"caption"` Caption string `json:"caption"`
Media string `json:"media"` Media string `json:"media"`
ParseMode ParseMode `json:"parse_mode,omitempty"`
// Video. // Video.
Width int `json:"width,omitempty"` Width int `json:"width,omitempty"`
@ -833,12 +793,7 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
Performer string `json:"performer,omitempty"` Performer string `json:"performer,omitempty"`
} }
resultMedia := &FileJSON{Media: mediaRepr} resultMedia := &FileJson{Media: mediaRepr}
sendOpts := extractOptions(options)
if sendOpts != nil {
resultMedia.ParseMode = sendOpts.ParseMode
}
switch y := inputMedia.(type) { switch y := inputMedia.(type) {
case *Photo: case *Photo:
@ -854,7 +809,7 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
resultMedia.MIME = y.MIME resultMedia.MIME = y.MIME
thumb = y.Thumbnail thumb = y.Thumbnail
if thumb != nil { if thumb != nil {
resultMedia.Thumbnail = "attach://" + thumbAttachName resultMedia.Thumbnail = "attach://thumb"
} }
case *Document: case *Document:
resultMedia.Type = "document" resultMedia.Type = "document"
@ -863,7 +818,7 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
resultMedia.MIME = y.MIME resultMedia.MIME = y.MIME
thumb = y.Thumbnail thumb = y.Thumbnail
if thumb != nil { if thumb != nil {
resultMedia.Thumbnail = "attach://" + thumbAttachName resultMedia.Thumbnail = "attach://thumb"
} }
case *Audio: case *Audio:
resultMedia.Type = "audio" resultMedia.Type = "audio"
@ -872,10 +827,6 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
resultMedia.MIME = y.MIME resultMedia.MIME = y.MIME
resultMedia.Title = y.Title resultMedia.Title = y.Title
resultMedia.Performer = y.Performer resultMedia.Performer = y.Performer
thumb = y.Thumbnail
if thumb != nil {
resultMedia.Thumbnail = "attach://" + thumbAttachName
}
default: default:
return nil, errors.Errorf("telebot: inputMedia entry is not valid") return nil, errors.Errorf("telebot: inputMedia entry is not valid")
} }
@ -895,9 +846,10 @@ func (b *Bot) EditMedia(message Editable, inputMedia InputMedia, options ...inte
} }
if thumb != nil { if thumb != nil {
file[thumbAttachName] = *thumb.MediaFile() file["thumb"] = *thumb.MediaFile()
} }
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts) embedSendOptions(params, sendOpts)
respJSON, err := b.sendFiles("editMessageMedia", file, params) respJSON, err := b.sendFiles("editMessageMedia", file, params)
@ -940,7 +892,7 @@ func (b *Bot) Delete(message Editable) error {
// Chat action is a status message that recipient would see where // Chat action is a status message that recipient would see where
// you typically see "Harry is typing" status message. The only // you typically see "Harry is typing" status message. The only
// difference is that bots' chat actions live only for 5 seconds // difference is that bots' chat actions live only for 5 seconds
// and die just once the client receives a message from the bot. // and die just once the client recieves a message from the bot.
// //
// Currently, Telegram supports only a narrow range of possible // Currently, Telegram supports only a narrow range of possible
// actions, these are aligned as constants of this package. // actions, these are aligned as constants of this package.
@ -1088,23 +1040,16 @@ func (b *Bot) GetFile(file *File) (io.ReadCloser, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// save FilePath
file.FilePath = f.FilePath
req, err := http.NewRequest("GET", b.URL+"/file/bot"+b.Token+"/"+f.FilePath, nil) url := fmt.Sprintf("%s/file/bot%s/%s",
if err != nil { b.URL, b.Token, f.FilePath)
return nil, wrapSystem(err)
}
resp, err := b.client.Do(req) resp, err := http.Get(url)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "file http.GET failed") return nil, err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, errors.Errorf("api error: expected 200 OK but got %s", resp.Status)
} }
// set FilePath
*file = f
return resp.Body, nil return resp.Body, nil
} }
@ -1117,7 +1062,7 @@ func (b *Bot) StopLiveLocation(message Editable, options ...interface{}) (*Messa
messageID, chatID := message.MessageSig() messageID, chatID := message.MessageSig()
params := map[string]string{ params := map[string]string{
"chat_id": strconv.FormatInt(chatID, 10), "chat_id": fmt.Sprintf("%d", chatID),
"message_id": messageID, "message_id": messageID,
} }
@ -1161,7 +1106,7 @@ func (b *Bot) GetInviteLink(chat *Chat) (string, error) {
return resp.Result, nil return resp.Result, nil
} }
// SetGroupTitle should be used to update group title. // SetChatTitle should be used to update group title.
func (b *Bot) SetGroupTitle(chat *Chat, newTitle string) error { func (b *Bot) SetGroupTitle(chat *Chat, newTitle string) error {
params := map[string]string{ params := map[string]string{
"chat_id": chat.Recipient(), "chat_id": chat.Recipient(),
@ -1410,141 +1355,5 @@ func (b *Bot) FileURLByID(fileID string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return b.URL + "/file/bot" + b.Token + "/" + f.FilePath, nil return fmt.Sprintf("%s/file/bot%s/%s", b.URL, b.Token, f.FilePath), nil
}
// UploadStickerFile returns uploaded File on success.
func (b *Bot) UploadStickerFile(userID int, pngSticker *File) (*File, error) {
files := map[string]File{
"png_sticker": *pngSticker,
}
params := map[string]string{
"user_id": strconv.Itoa(userID),
}
respJSON, err := b.sendFiles("uploadStickerFile", files, params)
if err != nil {
return nil, err
}
var resp struct {
Ok bool
Result File
Description string
}
err = json.Unmarshal(respJSON, &resp)
if err != nil {
return nil, err
}
if !resp.Ok {
return nil, errors.Errorf("api error: %s", resp.Description)
}
return &resp.Result, nil
}
// GetStickerSet returns StickerSet on success.
func (b *Bot) GetStickerSet(name string) (*StickerSet, error) {
respJSON, err := b.Raw("getStickerSet", map[string]string{"name": name})
if err != nil {
return nil, err
}
var resp struct {
Ok bool
Description string
Result *StickerSet
}
err = json.Unmarshal(respJSON, &resp)
if err != nil {
return nil, err
}
if !resp.Ok {
return nil, errors.Errorf("api error: %s", resp.Description)
}
return resp.Result, nil
}
// CreateNewStickerSet creates new sticker set.
func (b *Bot) CreateNewStickerSet(sp StickerSetParams, containsMasks bool, maskPosition MaskPosition) error {
files := map[string]File{
"png_sticker": *sp.PngSticker,
}
params := map[string]string{
"user_id": strconv.Itoa(sp.UserID),
"name": sp.Name,
"title": sp.Title,
"emojis": sp.Emojis,
}
if containsMasks {
mp, err := json.Marshal(&maskPosition)
if err != nil {
return err
}
params["mask_position"] = string(mp)
}
respJSON, err := b.sendFiles("createNewStickerSet", files, params)
if err != nil {
return err
}
return extractOkResponse(respJSON)
}
// AddStickerToSet adds new sticker to existing sticker set.
func (b *Bot) AddStickerToSet(sp StickerSetParams, maskPosition MaskPosition) error {
files := map[string]File{
"png_sticker": *sp.PngSticker,
}
params := map[string]string{
"user_id": strconv.Itoa(sp.UserID),
"name": sp.Name,
"title": sp.Title,
"emojis": sp.Emojis,
}
if maskPosition != (MaskPosition{}) {
mp, err := json.Marshal(&maskPosition)
if err != nil {
return err
}
params["mask_position"] = string(mp)
}
respJSON, err := b.sendFiles("addStickerToSet", files, params)
if err != nil {
return err
}
return extractOkResponse(respJSON)
}
// SetStickerPositionInSet moves a sticker in set to a specific position.
func (b *Bot) SetStickerPositionInSet(sticker string, position int) error {
params := map[string]string{
"sticker": sticker,
"position": strconv.Itoa(position),
}
respJSON, err := b.Raw("setStickerPositionInSet", params)
if err != nil {
return err
}
return extractOkResponse(respJSON)
}
// DeleteStickerFromSet deletes sticker from set created by the bot.
func (b *Bot) DeleteStickerFromSet(sticker string) error {
respJSON, err := b.Raw("deleteStickerFromSet", map[string]string{"sticker": sticker})
if err != nil {
return err
}
return extractOkResponse(respJSON)
} }

@ -109,9 +109,10 @@ const (
type ParseMode string type ParseMode string
const ( const (
ModeDefault ParseMode = "" ModeDefault ParseMode = ""
ModeMarkdown ParseMode = "Markdown" ModeMarkdown ParseMode = "MarkdownV2"
ModeHTML ParseMode = "HTML" ModeLegacyMarkdown ParseMode = "Markdown"
ModeHTML ParseMode = "HTML"
) )
// EntityType is a MessageEntity type. // EntityType is a MessageEntity type.
@ -129,6 +130,8 @@ const (
EntityCode EntityType = "code" EntityCode EntityType = "code"
EntityCodeBlock EntityType = "pre" EntityCodeBlock EntityType = "pre"
EntityTextLink EntityType = "text_link" EntityTextLink EntityType = "text_link"
EntityUnderline EntityType = "underline"
Strikethrough EntityType = "strikethrough"
) )
// ChatType represents one of the possible chat types. // ChatType represents one of the possible chat types.

Loading…
Cancel
Save