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