mirror of
https://github.com/tucnak/telebot
synced 2024-11-11 01:10:39 +00:00
telebot: rework media, implement Media and Inputtable interfaces
This commit is contained in:
parent
435b1e3b63
commit
0463e22543
5
api.go
5
api.go
@ -83,11 +83,12 @@ func (b *Bot) sendFiles(method string, files map[string]File, params map[string]
|
|||||||
|
|
||||||
pipeReader, pipeWriter := io.Pipe()
|
pipeReader, pipeWriter := io.Pipe()
|
||||||
writer := multipart.NewWriter(pipeWriter)
|
writer := multipart.NewWriter(pipeWriter)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer pipeWriter.Close()
|
defer pipeWriter.Close()
|
||||||
|
|
||||||
for field, file := range rawFiles {
|
for field, file := range rawFiles {
|
||||||
if err := addFileToWriter(writer, params["file_name"], field, file); err != nil {
|
if err := addFileToWriter(writer, files[field].fileName, field, file); err != nil {
|
||||||
pipeWriter.CloseWithError(err)
|
pipeWriter.CloseWithError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ func addFileToWriter(writer *multipart.Writer, filename, field string, file inte
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
reader = f
|
reader = f
|
||||||
} else {
|
} else {
|
||||||
return errors.Errorf("telebot: file for field %v should be an io.ReadCloser or string", field)
|
return errors.Errorf("telebot: file for field %v should be io.ReadCloser or string", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
part, err := writer.CreateFormFile(field, filename)
|
part, err := writer.CreateFormFile(field, filename)
|
||||||
|
159
bot.go
159
bot.go
@ -276,8 +276,8 @@ func (b *Bot) ProcessUpdate(upd Update) {
|
|||||||
match := cmdRx.FindAllStringSubmatch(m.Text, -1)
|
match := cmdRx.FindAllStringSubmatch(m.Text, -1)
|
||||||
if match != nil {
|
if match != nil {
|
||||||
// Syntax: "</command>@<bot> <payload>"
|
// Syntax: "</command>@<bot> <payload>"
|
||||||
|
|
||||||
command, botName := match[0][1], match[0][3]
|
command, botName := match[0][1], match[0][3]
|
||||||
|
|
||||||
if botName != "" && !strings.EqualFold(b.Me.Username, botName) {
|
if botName != "" && !strings.EqualFold(b.Me.Username, botName) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -301,11 +301,30 @@ func (b *Bot) ProcessUpdate(upd Update) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.Contact != nil {
|
||||||
|
b.handle(OnContact, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Location != nil {
|
||||||
|
b.handle(OnLocation, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Venue != nil {
|
||||||
|
b.handle(OnVenue, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Game != nil {
|
||||||
|
b.handle(OnGame, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Dice != nil {
|
||||||
|
b.handle(OnDice, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
if m.Invoice != nil {
|
if m.Invoice != nil {
|
||||||
b.handle(OnInvoice, c)
|
b.handle(OnInvoice, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Payment != nil {
|
if m.Payment != nil {
|
||||||
b.handle(OnPayment, c)
|
b.handle(OnPayment, c)
|
||||||
return
|
return
|
||||||
@ -526,16 +545,6 @@ func (b *Bot) handleMedia(c Context) bool {
|
|||||||
fired = b.handle(OnVideo, c)
|
fired = b.handle(OnVideo, c)
|
||||||
case m.VideoNote != nil:
|
case m.VideoNote != nil:
|
||||||
fired = b.handle(OnVideoNote, c)
|
fired = b.handle(OnVideoNote, c)
|
||||||
case m.Contact != nil:
|
|
||||||
fired = b.handle(OnContact, c)
|
|
||||||
case m.Location != nil:
|
|
||||||
fired = b.handle(OnLocation, c)
|
|
||||||
case m.Venue != nil:
|
|
||||||
fired = b.handle(OnVenue, c)
|
|
||||||
case m.Game != nil:
|
|
||||||
fired = b.handle(OnGame, c)
|
|
||||||
case m.Dice != nil:
|
|
||||||
fired = b.handle(OnDice, c)
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -585,6 +594,7 @@ func (b *Bot) SendAlbum(to Recipient, a Album, opts ...interface{}) ([]Message,
|
|||||||
return nil, ErrBadRecipient
|
return nil, ErrBadRecipient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendOpts := extractOptions(opts)
|
||||||
media := make([]string, len(a))
|
media := make([]string, len(a))
|
||||||
files := make(map[string]File)
|
files := make(map[string]File)
|
||||||
|
|
||||||
@ -607,41 +617,11 @@ func (b *Bot) SendAlbum(to Recipient, a Album, opts ...interface{}) ([]Message,
|
|||||||
return nil, errors.Errorf("telebot: album entry #%d does not exist", i)
|
return nil, errors.Errorf("telebot: album entry #%d does not exist", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch y := x.(type) {
|
im := x.InputMedia()
|
||||||
case *Photo:
|
im.Media = repr
|
||||||
data, _ = json.Marshal(struct {
|
im.ParseMode = sendOpts.ParseMode
|
||||||
Type string `json:"type"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
Caption string `json:"caption,omitempty"`
|
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
|
||||||
}{
|
|
||||||
Type: "photo",
|
|
||||||
Media: repr,
|
|
||||||
Caption: y.Caption,
|
|
||||||
ParseMode: y.ParseMode,
|
|
||||||
})
|
|
||||||
case *Video:
|
|
||||||
data, _ = json.Marshal(struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
Width int `json:"width,omitempty"`
|
|
||||||
Height int `json:"height,omitempty"`
|
|
||||||
Duration int `json:"duration,omitempty"`
|
|
||||||
SupportsStreaming bool `json:"supports_streaming,omitempty"`
|
|
||||||
}{
|
|
||||||
Type: "video",
|
|
||||||
Caption: y.Caption,
|
|
||||||
Media: repr,
|
|
||||||
Width: y.Width,
|
|
||||||
Height: y.Height,
|
|
||||||
Duration: y.Duration,
|
|
||||||
SupportsStreaming: y.SupportsStreaming,
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("telebot: album entry #%d is not valid", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
data, _ = json.Marshal(im)
|
||||||
media[i] = string(data)
|
media[i] = string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,8 +629,6 @@ func (b *Bot) SendAlbum(to Recipient, a Album, opts ...interface{}) ([]Message,
|
|||||||
"chat_id": to.Recipient(),
|
"chat_id": to.Recipient(),
|
||||||
"media": "[" + strings.Join(media, ",") + "]",
|
"media": "[" + strings.Join(media, ",") + "]",
|
||||||
}
|
}
|
||||||
|
|
||||||
sendOpts := extractOptions(opts)
|
|
||||||
b.embedSendOptions(params, sendOpts)
|
b.embedSendOptions(params, sendOpts)
|
||||||
|
|
||||||
data, err := b.sendFiles("sendMediaGroup", files, params)
|
data, err := b.sendFiles("sendMediaGroup", files, params)
|
||||||
@ -769,7 +747,7 @@ func (b *Bot) Edit(msg Editable, what interface{}, opts ...interface{}) (*Messag
|
|||||||
switch v := what.(type) {
|
switch v := what.(type) {
|
||||||
case *ReplyMarkup:
|
case *ReplyMarkup:
|
||||||
return b.EditReplyMarkup(msg, v)
|
return b.EditReplyMarkup(msg, v)
|
||||||
case InputMedia:
|
case Inputtable:
|
||||||
return b.EditMedia(msg, v, opts...)
|
return b.EditMedia(msg, v, opts...)
|
||||||
case string:
|
case string:
|
||||||
method = "editMessageText"
|
method = "editMessageText"
|
||||||
@ -889,14 +867,14 @@ func (b *Bot) EditCaption(msg Editable, caption string, opts ...interface{}) (*M
|
|||||||
// b.EditMedia(m, &tele.Photo{File: tele.FromDisk("chicken.jpg")})
|
// b.EditMedia(m, &tele.Photo{File: tele.FromDisk("chicken.jpg")})
|
||||||
// b.EditMedia(m, &tele.Video{File: tele.FromURL("http://video.mp4")})
|
// b.EditMedia(m, &tele.Video{File: tele.FromURL("http://video.mp4")})
|
||||||
//
|
//
|
||||||
func (b *Bot) EditMedia(msg Editable, media InputMedia, opts ...interface{}) (*Message, error) {
|
func (b *Bot) EditMedia(msg Editable, media Inputtable, opts ...interface{}) (*Message, error) {
|
||||||
var (
|
var (
|
||||||
repr string
|
repr string
|
||||||
thumb *Photo
|
|
||||||
|
|
||||||
thumbName = "thumb"
|
|
||||||
file = media.MediaFile()
|
file = media.MediaFile()
|
||||||
files = make(map[string]File)
|
files = make(map[string]File)
|
||||||
|
|
||||||
|
thumb *Photo
|
||||||
|
thumbName = "thumb"
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -915,76 +893,18 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, opts ...interface{}) (*M
|
|||||||
repr = "attach://" + s
|
repr = "attach://" + s
|
||||||
files[s] = *file
|
files[s] = *file
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("telebot: can't edit media, it does not exist")
|
return nil, errors.Errorf("telebot: cannot edit media, it does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileJSON struct {
|
|
||||||
// All types.
|
|
||||||
Type string `json:"type"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
|
||||||
|
|
||||||
// Video.
|
|
||||||
Width int `json:"width,omitempty"`
|
|
||||||
Height int `json:"height,omitempty"`
|
|
||||||
SupportsStreaming bool `json:"supports_streaming,omitempty"`
|
|
||||||
|
|
||||||
// Video and audio.
|
|
||||||
Duration int `json:"duration,omitempty"`
|
|
||||||
|
|
||||||
// Document.
|
|
||||||
FileName string `json:"file_name"`
|
|
||||||
|
|
||||||
// Document, video and audio.
|
|
||||||
Thumbnail string `json:"thumb,omitempty"`
|
|
||||||
MIME string `json:"mime_type,omitempty"`
|
|
||||||
|
|
||||||
// Audio.
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Performer string `json:"performer,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
result := &FileJSON{Media: repr}
|
|
||||||
|
|
||||||
switch m := media.(type) {
|
switch m := media.(type) {
|
||||||
case *Photo:
|
|
||||||
result.Type = "photo"
|
|
||||||
result.Caption = m.Caption
|
|
||||||
case *Video:
|
case *Video:
|
||||||
result.Type = "video"
|
|
||||||
result.Caption = m.Caption
|
|
||||||
result.Width = m.Width
|
|
||||||
result.Height = m.Height
|
|
||||||
result.Duration = m.Duration
|
|
||||||
result.SupportsStreaming = m.SupportsStreaming
|
|
||||||
result.MIME = m.MIME
|
|
||||||
thumb = m.Thumbnail
|
|
||||||
case *Document:
|
|
||||||
result.Type = "document"
|
|
||||||
result.Caption = m.Caption
|
|
||||||
result.FileName = m.FileName
|
|
||||||
result.MIME = m.MIME
|
|
||||||
thumb = m.Thumbnail
|
thumb = m.Thumbnail
|
||||||
case *Audio:
|
case *Audio:
|
||||||
result.Type = "audio"
|
thumb = m.Thumbnail
|
||||||
result.Caption = m.Caption
|
case *Document:
|
||||||
result.Duration = m.Duration
|
|
||||||
result.MIME = m.MIME
|
|
||||||
result.Title = m.Title
|
|
||||||
result.Performer = m.Performer
|
|
||||||
thumb = m.Thumbnail
|
thumb = m.Thumbnail
|
||||||
case *Animation:
|
case *Animation:
|
||||||
result.Type = "animation"
|
|
||||||
result.Caption = m.Caption
|
|
||||||
result.Width = m.Width
|
|
||||||
result.Height = m.Height
|
|
||||||
result.Duration = m.Duration
|
|
||||||
result.MIME = m.MIME
|
|
||||||
result.FileName = m.FileName
|
|
||||||
thumb = m.Thumbnail
|
thumb = m.Thumbnail
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("telebot: media entry is not valid")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msgID, chatID := msg.MessageSig()
|
msgID, chatID := msg.MessageSig()
|
||||||
@ -993,15 +913,16 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, opts ...interface{}) (*M
|
|||||||
sendOpts := extractOptions(opts)
|
sendOpts := extractOptions(opts)
|
||||||
b.embedSendOptions(params, sendOpts)
|
b.embedSendOptions(params, sendOpts)
|
||||||
|
|
||||||
if sendOpts != nil {
|
im := media.InputMedia()
|
||||||
result.ParseMode = params["parse_mode"]
|
im.Media = repr
|
||||||
}
|
im.ParseMode = sendOpts.ParseMode
|
||||||
|
|
||||||
if thumb != nil {
|
if thumb != nil {
|
||||||
result.Thumbnail = "attach://" + thumbName
|
im.Thumbnail = "attach://" + thumbName
|
||||||
files[thumbName] = *thumb.MediaFile()
|
files[thumbName] = *thumb.MediaFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
data, _ := json.Marshal(result)
|
data, _ := json.Marshal(im)
|
||||||
params["media"] = string(data)
|
params["media"] = string(data)
|
||||||
|
|
||||||
if chatID == 0 { // if inline message
|
if chatID == 0 { // if inline message
|
||||||
|
@ -405,7 +405,10 @@ func TestBot(t *testing.T) {
|
|||||||
_, err = b.SendAlbum(to, nil)
|
_, err = b.SendAlbum(to, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
msgs, err := b.SendAlbum(to, Album{photo, photo})
|
photo2 := *photo
|
||||||
|
photo2.Caption = ""
|
||||||
|
|
||||||
|
msgs, err := b.SendAlbum(to, Album{photo, &photo2}, ModeHTML)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, msgs, 2)
|
assert.Len(t, msgs, 2)
|
||||||
assert.NotEmpty(t, msgs[0].AlbumID)
|
assert.NotEmpty(t, msgs[0].AlbumID)
|
||||||
@ -427,7 +430,7 @@ func TestBot(t *testing.T) {
|
|||||||
b.parseMode = ModeDefault
|
b.parseMode = ModeDefault
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Edit(what=InputMedia)", func(t *testing.T) {
|
t.Run("Edit(what=Media)", func(t *testing.T) {
|
||||||
edited, err := b.Edit(msg, photo)
|
edited, err := b.Edit(msg, photo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, edited.Photo.UniqueID, photo.UniqueID)
|
assert.Equal(t, edited.Photo.UniqueID, photo.UniqueID)
|
||||||
@ -536,7 +539,7 @@ func TestBot(t *testing.T) {
|
|||||||
assert.NotNil(t, edited.Location)
|
assert.NotNil(t, edited.Location)
|
||||||
})
|
})
|
||||||
|
|
||||||
// should be the last
|
// Should be after the Edit tests.
|
||||||
t.Run("Delete()", func(t *testing.T) {
|
t.Run("Delete()", func(t *testing.T) {
|
||||||
require.NoError(t, b.Delete(msg))
|
require.NoError(t, b.Delete(msg))
|
||||||
})
|
})
|
||||||
|
11
file.go
11
file.go
@ -9,20 +9,21 @@ import (
|
|||||||
type File struct {
|
type File struct {
|
||||||
FileID string `json:"file_id"`
|
FileID string `json:"file_id"`
|
||||||
UniqueID string `json:"file_unique_id"`
|
UniqueID string `json:"file_unique_id"`
|
||||||
FileName string `json:"file_name"`
|
|
||||||
FileSize int `json:"file_size"`
|
FileSize int `json:"file_size"`
|
||||||
|
|
||||||
// file on telegram server https://core.telegram.org/bots/api#file
|
// FilePath is used for files on Telegram server.
|
||||||
FilePath string `json:"file_path"`
|
FilePath string `json:"file_path"`
|
||||||
|
|
||||||
// file on local file system.
|
// FileLocal uis ed for files on local file system.
|
||||||
FileLocal string `json:"file_local"`
|
FileLocal string `json:"file_local"`
|
||||||
|
|
||||||
// file on the internet
|
// FileURL is used for file on the internet.
|
||||||
FileURL string `json:"file_url"`
|
FileURL string `json:"file_url"`
|
||||||
|
|
||||||
// file backed with io.Reader
|
// FileReader is used for file backed with io.Reader.
|
||||||
FileReader io.Reader `json:"-"`
|
FileReader io.Reader `json:"-"`
|
||||||
|
|
||||||
|
fileName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromDisk constructs a new local (on-disk) file object.
|
// FromDisk constructs a new local (on-disk) file object.
|
||||||
|
147
media.go
147
media.go
@ -4,28 +4,50 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Album lets you group multiple media (so-called InputMedia)
|
// Media is a generic type for all kinds of media that includes File.
|
||||||
// into a single message.
|
type Media interface {
|
||||||
type Album []InputMedia
|
// MediaType returns string-represented media type.
|
||||||
|
MediaType() string
|
||||||
|
|
||||||
// InputMedia is a generic type for all kinds of media you
|
// MediaFile returns a pointer to the media file.
|
||||||
// can put into an album.
|
|
||||||
type InputMedia interface {
|
|
||||||
// As some files must be uploaded (instead of referencing)
|
|
||||||
// outer layers of Telebot require it.
|
|
||||||
MediaFile() *File
|
MediaFile() *File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InputMedia represents a composite InputMedia struct that is
|
||||||
|
// used by Telebot in sending and editing media methods.
|
||||||
|
type InputMedia struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Media string `json:"media"`
|
||||||
|
ParseMode string `json:"parse_mode"`
|
||||||
|
Thumbnail string `json:"thumb"`
|
||||||
|
|
||||||
|
*Photo
|
||||||
|
*Audio
|
||||||
|
*Video
|
||||||
|
*Document
|
||||||
|
*Animation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inputtable is a generic type for all kinds of media you
|
||||||
|
// can put into an album.
|
||||||
|
type Inputtable interface {
|
||||||
|
Media
|
||||||
|
|
||||||
|
// InputMedia returns already marshalled InputMedia type
|
||||||
|
// ready to be used in sending and editing media methods.
|
||||||
|
InputMedia() InputMedia
|
||||||
|
}
|
||||||
|
|
||||||
|
// Album lets you group multiple media into a single message.
|
||||||
|
type Album []Inputtable
|
||||||
|
|
||||||
// Photo object represents a single photo file.
|
// Photo object represents a single photo file.
|
||||||
type Photo struct {
|
type Photo struct {
|
||||||
File
|
File
|
||||||
|
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
|
|
||||||
// (Optional)
|
|
||||||
Caption string `json:"caption,omitempty"`
|
Caption string `json:"caption,omitempty"`
|
||||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type photoSize struct {
|
type photoSize struct {
|
||||||
@ -36,27 +58,36 @@ type photoSize struct {
|
|||||||
Caption string `json:"caption,omitempty"`
|
Caption string `json:"caption,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaFile returns &Photo.File
|
func (p *Photo) MediaType() string {
|
||||||
|
return "photo"
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Photo) MediaFile() *File {
|
func (p *Photo) MediaFile() *File {
|
||||||
return &p.File
|
return &p.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Photo) InputMedia() InputMedia {
|
||||||
|
return InputMedia{
|
||||||
|
Type: p.MediaType(),
|
||||||
|
Photo: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON is custom unmarshaller required to abstract
|
// UnmarshalJSON is custom unmarshaller required to abstract
|
||||||
// away the hassle of treating different thumbnail sizes.
|
// away the hassle of treating different thumbnail sizes.
|
||||||
// Instead, Telebot chooses the hi-res one and just sticks to it.
|
// Instead, Telebot chooses the hi-res one and just sticks to it.
|
||||||
//
|
//
|
||||||
// I really do find it a beautiful solution.
|
// I really do find it a beautiful solution.
|
||||||
func (p *Photo) UnmarshalJSON(jsonStr []byte) error {
|
func (p *Photo) UnmarshalJSON(data []byte) error {
|
||||||
var hq photoSize
|
var hq photoSize
|
||||||
|
|
||||||
if jsonStr[0] == '{' {
|
if data[0] == '{' {
|
||||||
if err := json.Unmarshal(jsonStr, &hq); err != nil {
|
if err := json.Unmarshal(data, &hq); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var sizes []photoSize
|
var sizes []photoSize
|
||||||
|
if err := json.Unmarshal(data, &sizes); err != nil {
|
||||||
if err := json.Unmarshal(jsonStr, &sizes); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,11 +116,22 @@ type Audio struct {
|
|||||||
FileName string `json:"file_name,omitempty"`
|
FileName string `json:"file_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaFile returns &Audio.File
|
func (a *Audio) MediaType() string {
|
||||||
|
return "audio"
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Audio) MediaFile() *File {
|
func (a *Audio) MediaFile() *File {
|
||||||
|
a.fileName = a.FileName
|
||||||
return &a.File
|
return &a.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Audio) InputMedia() InputMedia {
|
||||||
|
return InputMedia{
|
||||||
|
Type: a.MediaType(),
|
||||||
|
Audio: a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Document object represents a general file (as opposed to Photo or Audio).
|
// Document object represents a general file (as opposed to Photo or Audio).
|
||||||
// Telegram users can send files of any type of up to 1.5 GB in size.
|
// Telegram users can send files of any type of up to 1.5 GB in size.
|
||||||
type Document struct {
|
type Document struct {
|
||||||
@ -102,11 +144,22 @@ type Document struct {
|
|||||||
FileName string `json:"file_name,omitempty"`
|
FileName string `json:"file_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaFile returns &Document.File
|
func (d *Document) MediaType() string {
|
||||||
|
return "document"
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Document) MediaFile() *File {
|
func (d *Document) MediaFile() *File {
|
||||||
|
d.fileName = d.FileName
|
||||||
return &d.File
|
return &d.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) InputMedia() InputMedia {
|
||||||
|
return InputMedia{
|
||||||
|
Type: d.MediaType(),
|
||||||
|
Document: d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Video object represents a video file.
|
// Video object represents a video file.
|
||||||
type Video struct {
|
type Video struct {
|
||||||
File
|
File
|
||||||
@ -123,11 +176,22 @@ type Video struct {
|
|||||||
FileName string `json:"file_name,omitempty"`
|
FileName string `json:"file_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaFile returns &Video.File
|
func (v *Video) MediaType() string {
|
||||||
|
return "video"
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Video) MediaFile() *File {
|
func (v *Video) MediaFile() *File {
|
||||||
|
v.fileName = v.FileName
|
||||||
return &v.File
|
return &v.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Video) InputMedia() InputMedia {
|
||||||
|
return InputMedia{
|
||||||
|
Type: v.MediaType(),
|
||||||
|
Video: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Animation object represents a animation file.
|
// Animation object represents a animation file.
|
||||||
type Animation struct {
|
type Animation struct {
|
||||||
File
|
File
|
||||||
@ -143,11 +207,22 @@ type Animation struct {
|
|||||||
FileName string `json:"file_name,omitempty"`
|
FileName string `json:"file_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaFile returns &Animation.File
|
func (a *Animation) MediaType() string {
|
||||||
|
return "animation"
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Animation) MediaFile() *File {
|
func (a *Animation) MediaFile() *File {
|
||||||
|
a.fileName = a.FileName
|
||||||
return &a.File
|
return &a.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Animation) InputMedia() InputMedia {
|
||||||
|
return InputMedia{
|
||||||
|
Type: a.MediaType(),
|
||||||
|
Animation: a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Voice object represents a voice note.
|
// Voice object represents a voice note.
|
||||||
type Voice struct {
|
type Voice struct {
|
||||||
File
|
File
|
||||||
@ -159,10 +234,18 @@ type Voice struct {
|
|||||||
MIME string `json:"mime_type,omitempty"`
|
MIME string `json:"mime_type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VideoNote represents a video message (available in Telegram apps
|
func (v *Voice) MediaType() string {
|
||||||
// as of v.4.0).
|
return "voice"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voice) MediaFile() *File {
|
||||||
|
return &v.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoNote represents a video message.
|
||||||
type VideoNote struct {
|
type VideoNote struct {
|
||||||
File
|
File
|
||||||
|
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
|
|
||||||
// (Optional)
|
// (Optional)
|
||||||
@ -170,7 +253,15 @@ type VideoNote struct {
|
|||||||
Length int `json:"length,omitempty"`
|
Length int `json:"length,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contact object represents a contact to Telegram user
|
func (v *VideoNote) MediaType() string {
|
||||||
|
return "video_note"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VideoNote) MediaFile() *File {
|
||||||
|
return &v.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contact object represents a contact to Telegram user.
|
||||||
type Contact struct {
|
type Contact struct {
|
||||||
PhoneNumber string `json:"phone_number"`
|
PhoneNumber string `json:"phone_number"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
@ -193,14 +284,6 @@ type Location struct {
|
|||||||
LivePeriod int `json:"live_period,omitempty"`
|
LivePeriod int `json:"live_period,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProximityAlert sent whenever
|
|
||||||
// a user in the chat triggers a proximity alert set by another user.
|
|
||||||
type ProximityAlert struct {
|
|
||||||
Traveler *User `json:"traveler,omitempty"`
|
|
||||||
Watcher *User `json:"watcher,omitempty"`
|
|
||||||
Distance int `json:"distance"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Venue object represents a venue location with name, address and
|
// Venue object represents a venue location with name, address and
|
||||||
// optional foursquare ID.
|
// optional foursquare ID.
|
||||||
type Venue struct {
|
type Venue struct {
|
||||||
|
@ -270,6 +270,14 @@ type MessageEntity struct {
|
|||||||
// Entities is used to set message's text entities as a send option.
|
// Entities is used to set message's text entities as a send option.
|
||||||
type Entities []MessageEntity
|
type Entities []MessageEntity
|
||||||
|
|
||||||
|
// ProximityAlert sent whenever a user in the chat triggers
|
||||||
|
// a proximity alert set by another user.
|
||||||
|
type ProximityAlert struct {
|
||||||
|
Traveler *User `json:"traveler,omitempty"`
|
||||||
|
Watcher *User `json:"watcher,omitempty"`
|
||||||
|
Distance int `json:"distance"`
|
||||||
|
}
|
||||||
|
|
||||||
// AutoDeleteTimer represents a service message about a change in auto-delete timer settings.
|
// AutoDeleteTimer represents a service message about a change in auto-delete timer settings.
|
||||||
type AutoDeleteTimer struct {
|
type AutoDeleteTimer struct {
|
||||||
Unixtime int `json:"message_auto_delete_time"`
|
Unixtime int `json:"message_auto_delete_time"`
|
||||||
|
15
util.go
15
util.go
@ -132,24 +132,17 @@ func extractMessage(data []byte) (*Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func extractOptions(how []interface{}) *SendOptions {
|
func extractOptions(how []interface{}) *SendOptions {
|
||||||
var opts *SendOptions
|
opts := &SendOptions{}
|
||||||
|
|
||||||
for _, prop := range how {
|
for _, prop := range how {
|
||||||
switch opt := prop.(type) {
|
switch opt := prop.(type) {
|
||||||
case *SendOptions:
|
case *SendOptions:
|
||||||
opts = opt.copy()
|
opts = opt.copy()
|
||||||
case *ReplyMarkup:
|
case *ReplyMarkup:
|
||||||
if opts == nil {
|
|
||||||
opts = &SendOptions{}
|
|
||||||
}
|
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
opts.ReplyMarkup = opt.copy()
|
opts.ReplyMarkup = opt.copy()
|
||||||
}
|
}
|
||||||
case Option:
|
case Option:
|
||||||
if opts == nil {
|
|
||||||
opts = &SendOptions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch opt {
|
switch opt {
|
||||||
case NoPreview:
|
case NoPreview:
|
||||||
opts.DisableWebPagePreview = true
|
opts.DisableWebPagePreview = true
|
||||||
@ -174,14 +167,8 @@ func extractOptions(how []interface{}) *SendOptions {
|
|||||||
panic("telebot: unsupported flag-option")
|
panic("telebot: unsupported flag-option")
|
||||||
}
|
}
|
||||||
case ParseMode:
|
case ParseMode:
|
||||||
if opts == nil {
|
|
||||||
opts = &SendOptions{}
|
|
||||||
}
|
|
||||||
opts.ParseMode = opt
|
opts.ParseMode = opt
|
||||||
case Entities:
|
case Entities:
|
||||||
if opts == nil {
|
|
||||||
opts = &SendOptions{}
|
|
||||||
}
|
|
||||||
opts.Entities = opt
|
opts.Entities = opt
|
||||||
default:
|
default:
|
||||||
panic("telebot: unsupported send-option")
|
panic("telebot: unsupported send-option")
|
||||||
|
Loading…
Reference in New Issue
Block a user