types.go (view raw)
1package tgbotapi
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "net/url"
8 "strings"
9 "time"
10)
11
12// APIResponse is a response from the Telegram API with the result
13// stored raw.
14type APIResponse struct {
15 Ok bool `json:"ok"`
16 Result json.RawMessage `json:"result"`
17 ErrorCode int `json:"error_code"`
18 Description string `json:"description"`
19 Parameters *ResponseParameters `json:"parameters"`
20}
21
22// ResponseParameters are various errors that can be returned in APIResponse.
23type ResponseParameters struct {
24 MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
25 RetryAfter int `json:"retry_after"` // optional
26}
27
28// Update is an update response, from GetUpdates.
29type Update struct {
30 UpdateID int `json:"update_id"`
31 Message *Message `json:"message"`
32 EditedMessage *Message `json:"edited_message"`
33 ChannelPost *Message `json:"channel_post"`
34 EditedChannelPost *Message `json:"edited_channel_post"`
35 InlineQuery *InlineQuery `json:"inline_query"`
36 ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
37 CallbackQuery *CallbackQuery `json:"callback_query"`
38}
39
40//updatesChannel is the channel for getting updates.
41type updatesChannel <-chan Update
42
43//Clear discards all the actual incoming updates
44func (ch updatesChannel) Clear() {
45 for len(ch) != 0 {
46 <-ch
47 }
48}
49
50// User is a user on Telegram.
51type User struct {
52 ID int `json:"id"`
53 FirstName string `json:"first_name"`
54 LastName string `json:"last_name"` // optional
55 UserName string `json:"username"` // optional
56}
57
58// String displays a simple text version of a user.
59//
60// It is normally a user's username, but falls back to a first/last
61// name as available.
62func (u *User) String() string {
63 if u.UserName != "" {
64 return u.UserName
65 }
66
67 name := u.FirstName
68 if u.LastName != "" {
69 name += " " + u.LastName
70 }
71
72 return name
73}
74
75// GroupChat is a group chat.
76type GroupChat struct {
77 ID int `json:"id"`
78 Title string `json:"title"`
79}
80
81// Chat contains information about the place a message was sent.
82type Chat struct {
83 ID int64 `json:"id"`
84 Type string `json:"type"`
85 Title string `json:"title"` // optional
86 UserName string `json:"username"` // optional
87 FirstName string `json:"first_name"` // optional
88 LastName string `json:"last_name"` // optional
89 AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
90}
91
92// IsPrivate returns if the Chat is a private conversation.
93func (c Chat) IsPrivate() bool {
94 return c.Type == "private"
95}
96
97// IsGroup returns if the Chat is a group.
98func (c Chat) IsGroup() bool {
99 return c.Type == "group"
100}
101
102// IsSuperGroup returns if the Chat is a supergroup.
103func (c Chat) IsSuperGroup() bool {
104 return c.Type == "supergroup"
105}
106
107// IsChannel returns if the Chat is a channel.
108func (c Chat) IsChannel() bool {
109 return c.Type == "channel"
110}
111
112// ChatConfig returns a ChatConfig struct for chat related methods.
113func (c Chat) ChatConfig() ChatConfig {
114 return ChatConfig{ChatID: c.ID}
115}
116
117// Message is returned by almost every request, and contains data about
118// almost anything.
119type Message struct {
120 MessageID int `json:"message_id"`
121 From *User `json:"from"` // optional
122 Date int `json:"date"`
123 Chat *Chat `json:"chat"`
124 ForwardFrom *User `json:"forward_from"` // optional
125 ForwardFromChat *Chat `json:"forward_from_chat"` // optional
126 ForwardFromMessageID int `json:"forward_from_message_id"` // optional
127 ForwardDate int `json:"forward_date"` // optional
128 ReplyToMessage *Message `json:"reply_to_message"` // optional
129 EditDate int `json:"edit_date"` // optional
130 Text string `json:"text"` // optional
131 Entities *[]MessageEntity `json:"entities"` // optional
132 Audio *Audio `json:"audio"` // optional
133 Document *Document `json:"document"` // optional
134 Game *Game `json:"game"` // optional
135 Photo *[]PhotoSize `json:"photo"` // optional
136 Sticker *Sticker `json:"sticker"` // optional
137 Video *Video `json:"video"` // optional
138 Voice *Voice `json:"voice"` // optional
139 Caption string `json:"caption"` // optional
140 Contact *Contact `json:"contact"` // optional
141 Location *Location `json:"location"` // optional
142 Venue *Venue `json:"venue"` // optional
143 NewChatMember *User `json:"new_chat_member"` // optional
144 LeftChatMember *User `json:"left_chat_member"` // optional
145 NewChatTitle string `json:"new_chat_title"` // optional
146 NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
147 DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
148 GroupChatCreated bool `json:"group_chat_created"` // optional
149 SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
150 ChannelChatCreated bool `json:"channel_chat_created"` // optional
151 MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
152 MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
153 PinnedMessage *Message `json:"pinned_message"` // optional
154}
155
156// Time converts the message timestamp into a Time.
157func (m *Message) Time() time.Time {
158 return time.Unix(int64(m.Date), 0)
159}
160
161// IsCommand returns true if message starts with '/'.
162func (m *Message) IsCommand() bool {
163 return m.Text != "" && m.Text[0] == '/'
164}
165
166// Command checks if the message was a command and if it was, returns the
167// command. If the Message was not a command, it returns an empty string.
168//
169// If the command contains the at bot syntax, it removes the bot name.
170func (m *Message) Command() string {
171 if !m.IsCommand() {
172 return ""
173 }
174
175 command := strings.SplitN(m.Text, " ", 2)[0][1:]
176
177 if i := strings.Index(command, "@"); i != -1 {
178 command = command[:i]
179 }
180
181 return command
182}
183
184// CommandArguments checks if the message was a command and if it was,
185// returns all text after the command name. If the Message was not a
186// command, it returns an empty string.
187func (m *Message) CommandArguments() string {
188 if !m.IsCommand() {
189 return ""
190 }
191
192 split := strings.SplitN(m.Text, " ", 2)
193 if len(split) != 2 {
194 return ""
195 }
196
197 return strings.SplitN(m.Text, " ", 2)[1]
198}
199
200// MessageEntity contains information about data in a Message.
201type MessageEntity struct {
202 Type string `json:"type"`
203 Offset int `json:"offset"`
204 Length int `json:"length"`
205 URL string `json:"url"` // optional
206 User *User `json:"user"` // optional
207}
208
209// ParseURL attempts to parse a URL contained within a MessageEntity.
210func (entity MessageEntity) ParseURL() (*url.URL, error) {
211 if entity.URL == "" {
212 return nil, errors.New(ErrBadURL)
213 }
214
215 return url.Parse(entity.URL)
216}
217
218// PhotoSize contains information about photos.
219type PhotoSize struct {
220 FileID string `json:"file_id"`
221 Width int `json:"width"`
222 Height int `json:"height"`
223 FileSize int `json:"file_size"` // optional
224}
225
226// Audio contains information about audio.
227type Audio struct {
228 FileID string `json:"file_id"`
229 Duration int `json:"duration"`
230 Performer string `json:"performer"` // optional
231 Title string `json:"title"` // optional
232 MimeType string `json:"mime_type"` // optional
233 FileSize int `json:"file_size"` // optional
234}
235
236// Document contains information about a document.
237type Document struct {
238 FileID string `json:"file_id"`
239 Thumbnail *PhotoSize `json:"thumb"` // optional
240 FileName string `json:"file_name"` // optional
241 MimeType string `json:"mime_type"` // optional
242 FileSize int `json:"file_size"` // optional
243}
244
245// Sticker contains information about a sticker.
246type Sticker struct {
247 FileID string `json:"file_id"`
248 Width int `json:"width"`
249 Height int `json:"height"`
250 Thumbnail *PhotoSize `json:"thumb"` // optional
251 Emoji string `json:"emoji"` // optional
252 FileSize int `json:"file_size"` // optional
253}
254
255// Video contains information about a video.
256type Video struct {
257 FileID string `json:"file_id"`
258 Width int `json:"width"`
259 Height int `json:"height"`
260 Duration int `json:"duration"`
261 Thumbnail *PhotoSize `json:"thumb"` // optional
262 MimeType string `json:"mime_type"` // optional
263 FileSize int `json:"file_size"` // optional
264}
265
266// Voice contains information about a voice.
267type Voice struct {
268 FileID string `json:"file_id"`
269 Duration int `json:"duration"`
270 MimeType string `json:"mime_type"` // optional
271 FileSize int `json:"file_size"` // optional
272}
273
274// Contact contains information about a contact.
275//
276// Note that LastName and UserID may be empty.
277type Contact struct {
278 PhoneNumber string `json:"phone_number"`
279 FirstName string `json:"first_name"`
280 LastName string `json:"last_name"` // optional
281 UserID int `json:"user_id"` // optional
282}
283
284// Location contains information about a place.
285type Location struct {
286 Longitude float64 `json:"longitude"`
287 Latitude float64 `json:"latitude"`
288}
289
290// Venue contains information about a venue, including its Location.
291type Venue struct {
292 Location Location `json:"location"`
293 Title string `json:"title"`
294 Address string `json:"address"`
295 FoursquareID string `json:"foursquare_id"` // optional
296}
297
298// UserProfilePhotos contains a set of user profile photos.
299type UserProfilePhotos struct {
300 TotalCount int `json:"total_count"`
301 Photos [][]PhotoSize `json:"photos"`
302}
303
304// File contains information about a file to download from Telegram.
305type File struct {
306 FileID string `json:"file_id"`
307 FileSize int `json:"file_size"` // optional
308 FilePath string `json:"file_path"` // optional
309}
310
311// Link returns a full path to the download URL for a File.
312//
313// It requires the Bot Token to create the link.
314func (f *File) Link(token string) string {
315 return fmt.Sprintf(FileEndpoint, token, f.FilePath)
316}
317
318// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
319type ReplyKeyboardMarkup struct {
320 Keyboard [][]KeyboardButton `json:"keyboard"`
321 ResizeKeyboard bool `json:"resize_keyboard"` // optional
322 OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
323 Selective bool `json:"selective"` // optional
324}
325
326// KeyboardButton is a button within a custom keyboard.
327type KeyboardButton struct {
328 Text string `json:"text"`
329 RequestContact bool `json:"request_contact"`
330 RequestLocation bool `json:"request_location"`
331}
332
333// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
334type ReplyKeyboardHide struct {
335 HideKeyboard bool `json:"hide_keyboard"`
336 Selective bool `json:"selective"` // optional
337}
338
339// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
340type ReplyKeyboardRemove struct {
341 RemoveKeyboard bool `json:"remove_keyboard"`
342 Selective bool `json:"selective"`
343}
344
345// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
346type InlineKeyboardMarkup struct {
347 InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
348}
349
350// InlineKeyboardButton is a button within a custom keyboard for
351// inline query responses.
352//
353// Note that some values are references as even an empty string
354// will change behavior.
355//
356// CallbackGame, if set, MUST be first button in first row.
357type InlineKeyboardButton struct {
358 Text string `json:"text"`
359 URL *string `json:"url,omitempty"` // optional
360 CallbackData *string `json:"callback_data,omitempty"` // optional
361 SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
362 SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat"` // optional
363 CallbackGame *CallbackGame `json:"callback_game"` // optional
364}
365
366// CallbackQuery is data sent when a keyboard button with callback data
367// is clicked.
368type CallbackQuery struct {
369 ID string `json:"id"`
370 From *User `json:"from"`
371 Message *Message `json:"message"` // optional
372 InlineMessageID string `json:"inline_message_id"` // optional
373 ChatInstance string `json:"chat_instance"`
374 Data string `json:"data"` // optional
375 GameShortName string `json:"game_short_name"` // optional
376}
377
378// ForceReply allows the Bot to have users directly reply to it without
379// additional interaction.
380type ForceReply struct {
381 ForceReply bool `json:"force_reply"`
382 Selective bool `json:"selective"` // optional
383}
384
385// ChatMember is information about a member in a chat.
386type ChatMember struct {
387 User *User `json:"user"`
388 Status string `json:"status"`
389}
390
391// IsCreator returns if the ChatMember was the creator of the chat.
392func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
393
394// IsAdministrator returns if the ChatMember is a chat administrator.
395func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
396
397// IsMember returns if the ChatMember is a current member of the chat.
398func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
399
400// HasLeft returns if the ChatMember left the chat.
401func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
402
403// WasKicked returns if the ChatMember was kicked from the chat.
404func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
405
406// Game is a game within Telegram.
407type Game struct {
408 Title string `json:"title"`
409 Description string `json:"description"`
410 Photo []PhotoSize `json:"photo"`
411 Text string `json:"text"`
412 TextEntities []MessageEntity `json:"text_entities"`
413 Animation Animation `json:"animation"`
414}
415
416// Animation is a GIF animation demonstrating the game.
417type Animation struct {
418 FileID string `json:"file_id"`
419 Thumb PhotoSize `json:"thumb"`
420 FileName string `json:"file_name"`
421 MimeType string `json:"mime_type"`
422 FileSize int `json:"file_size"`
423}
424
425// GameHighScore is a user's score and position on the leaderboard.
426type GameHighScore struct {
427 Position int `json:"position"`
428 User User `json:"user"`
429 Score int `json:"score"`
430}
431
432// CallbackGame is for starting a game in an inline keyboard button.
433type CallbackGame struct{}
434
435// WebhookInfo is information about a currently set webhook.
436type WebhookInfo struct {
437 URL string `json:"url"`
438 HasCustomCertificate bool `json:"has_custom_certificate"`
439 PendingUpdateCount int `json:"pending_update_count"`
440 LastErrorDate int `json:"last_error_date"` // optional
441 LastErrorMessage string `json:"last_error_message"` // optional
442}
443
444// IsSet returns true if a webhook is currently set.
445func (info WebhookInfo) IsSet() bool {
446 return info.URL != ""
447}
448
449// InlineQuery is a Query from Telegram for an inline request.
450type InlineQuery struct {
451 ID string `json:"id"`
452 From *User `json:"from"`
453 Location *Location `json:"location"` // optional
454 Query string `json:"query"`
455 Offset string `json:"offset"`
456}
457
458// InlineQueryResultArticle is an inline query response article.
459type InlineQueryResultArticle struct {
460 Type string `json:"type"` // required
461 ID string `json:"id"` // required
462 Title string `json:"title"` // required
463 InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
464 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
465 URL string `json:"url"`
466 HideURL bool `json:"hide_url"`
467 Description string `json:"description"`
468 ThumbURL string `json:"thumb_url"`
469 ThumbWidth int `json:"thumb_width"`
470 ThumbHeight int `json:"thumb_height"`
471}
472
473// InlineQueryResultPhoto is an inline query response photo.
474type InlineQueryResultPhoto struct {
475 Type string `json:"type"` // required
476 ID string `json:"id"` // required
477 URL string `json:"photo_url"` // required
478 MimeType string `json:"mime_type"`
479 Width int `json:"photo_width"`
480 Height int `json:"photo_height"`
481 ThumbURL string `json:"thumb_url"`
482 Title string `json:"title"`
483 Description string `json:"description"`
484 Caption string `json:"caption"`
485 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
486 InputMessageContent interface{} `json:"input_message_content,omitempty"`
487}
488
489// InlineQueryResultGIF is an inline query response GIF.
490type InlineQueryResultGIF struct {
491 Type string `json:"type"` // required
492 ID string `json:"id"` // required
493 URL string `json:"gif_url"` // required
494 Width int `json:"gif_width"`
495 Height int `json:"gif_height"`
496 ThumbURL string `json:"thumb_url"`
497 Title string `json:"title"`
498 Caption string `json:"caption"`
499 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
500 InputMessageContent interface{} `json:"input_message_content,omitempty"`
501}
502
503// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
504type InlineQueryResultMPEG4GIF struct {
505 Type string `json:"type"` // required
506 ID string `json:"id"` // required
507 URL string `json:"mpeg4_url"` // required
508 Width int `json:"mpeg4_width"`
509 Height int `json:"mpeg4_height"`
510 ThumbURL string `json:"thumb_url"`
511 Title string `json:"title"`
512 Caption string `json:"caption"`
513 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
514 InputMessageContent interface{} `json:"input_message_content,omitempty"`
515}
516
517// InlineQueryResultVideo is an inline query response video.
518type InlineQueryResultVideo struct {
519 Type string `json:"type"` // required
520 ID string `json:"id"` // required
521 URL string `json:"video_url"` // required
522 MimeType string `json:"mime_type"` // required
523 ThumbURL string `json:"thumb_url"`
524 Title string `json:"title"`
525 Caption string `json:"caption"`
526 Width int `json:"video_width"`
527 Height int `json:"video_height"`
528 Duration int `json:"video_duration"`
529 Description string `json:"description"`
530 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
531 InputMessageContent interface{} `json:"input_message_content,omitempty"`
532}
533
534// InlineQueryResultAudio is an inline query response audio.
535type InlineQueryResultAudio struct {
536 Type string `json:"type"` // required
537 ID string `json:"id"` // required
538 URL string `json:"audio_url"` // required
539 Title string `json:"title"` // required
540 Caption string `json:"caption"`
541 Performer string `json:"performer"`
542 Duration int `json:"audio_duration"`
543 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
544 InputMessageContent interface{} `json:"input_message_content,omitempty"`
545}
546
547// InlineQueryResultVoice is an inline query response voice.
548type InlineQueryResultVoice struct {
549 Type string `json:"type"` // required
550 ID string `json:"id"` // required
551 URL string `json:"voice_url"` // required
552 Title string `json:"title"` // required
553 Caption string `json:"caption"`
554 Duration int `json:"voice_duration"`
555 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
556 InputMessageContent interface{} `json:"input_message_content,omitempty"`
557}
558
559// InlineQueryResultDocument is an inline query response document.
560type InlineQueryResultDocument struct {
561 Type string `json:"type"` // required
562 ID string `json:"id"` // required
563 Title string `json:"title"` // required
564 Caption string `json:"caption"`
565 URL string `json:"document_url"` // required
566 MimeType string `json:"mime_type"` // required
567 Description string `json:"description"`
568 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
569 InputMessageContent interface{} `json:"input_message_content,omitempty"`
570 ThumbURL string `json:"thumb_url"`
571 ThumbWidth int `json:"thumb_width"`
572 ThumbHeight int `json:"thumb_height"`
573}
574
575// InlineQueryResultLocation is an inline query response location.
576type InlineQueryResultLocation struct {
577 Type string `json:"type"` // required
578 ID string `json:"id"` // required
579 Latitude float64 `json:"latitude"` // required
580 Longitude float64 `json:"longitude"` // required
581 Title string `json:"title"` // required
582 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
583 InputMessageContent interface{} `json:"input_message_content,omitempty"`
584 ThumbURL string `json:"thumb_url"`
585 ThumbWidth int `json:"thumb_width"`
586 ThumbHeight int `json:"thumb_height"`
587}
588
589// InlineQueryResultGame is an inline query response game.
590type InlineQueryResultGame struct {
591 Type string `json:"type"`
592 ID string `json:"id"`
593 GameShortName string `json:"game_short_name"`
594 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup"`
595}
596
597// ChosenInlineResult is an inline query result chosen by a User
598type ChosenInlineResult struct {
599 ResultID string `json:"result_id"`
600 From *User `json:"from"`
601 Location *Location `json:"location"`
602 InlineMessageID string `json:"inline_message_id"`
603 Query string `json:"query"`
604}
605
606// InputTextMessageContent contains text for displaying
607// as an inline query result.
608type InputTextMessageContent struct {
609 Text string `json:"message_text"`
610 ParseMode string `json:"parse_mode"`
611 DisableWebPagePreview bool `json:"disable_web_page_preview"`
612}
613
614// InputLocationMessageContent contains a location for displaying
615// as an inline query result.
616type InputLocationMessageContent struct {
617 Latitude float64 `json:"latitude"`
618 Longitude float64 `json:"longitude"`
619}
620
621// InputVenueMessageContent contains a venue for displaying
622// as an inline query result.
623type InputVenueMessageContent struct {
624 Latitude float64 `json:"latitude"`
625 Longitude float64 `json:"longitude"`
626 Title string `json:"title"`
627 Address string `json:"address"`
628 FoursquareID string `json:"foursquare_id"`
629}
630
631// InputContactMessageContent contains a contact for displaying
632// as an inline query result.
633type InputContactMessageContent struct {
634 PhoneNumber string `json:"phone_number"`
635 FirstName string `json:"first_name"`
636 LastName string `json:"last_name"`
637}