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