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}
20
21// Update is an update response, from GetUpdates.
22type Update struct {
23 UpdateID int `json:"update_id"`
24 Message *Message `json:"message"`
25 InlineQuery *InlineQuery `json:"inline_query"`
26 ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
27 CallbackQuery *CallbackQuery `json:"callback_query"`
28}
29
30// User is a user on Telegram.
31type User struct {
32 ID int `json:"id"`
33 FirstName string `json:"first_name"`
34 LastName string `json:"last_name"` // optional
35 UserName string `json:"username"` // optional
36}
37
38// String displays a simple text version of a user.
39//
40// It is normally a user's username, but falls back to a first/last
41// name as available.
42func (u *User) String() string {
43 if u.UserName != "" {
44 return u.UserName
45 }
46
47 name := u.FirstName
48 if u.LastName != "" {
49 name += " " + u.LastName
50 }
51
52 return name
53}
54
55// GroupChat is a group chat.
56type GroupChat struct {
57 ID int `json:"id"`
58 Title string `json:"title"`
59}
60
61// Chat contains information about the place a message was sent.
62type Chat struct {
63 ID int64 `json:"id"`
64 Type string `json:"type"`
65 Title string `json:"title"` // optional
66 UserName string `json:"username"` // optional
67 FirstName string `json:"first_name"` // optional
68 LastName string `json:"last_name"` // optional
69}
70
71// IsPrivate returns if the Chat is a private conversation.
72func (c *Chat) IsPrivate() bool {
73 return c.Type == "private"
74}
75
76// IsGroup returns if the Chat is a group.
77func (c *Chat) IsGroup() bool {
78 return c.Type == "group"
79}
80
81// IsSuperGroup returns if the Chat is a supergroup.
82func (c *Chat) IsSuperGroup() bool {
83 return c.Type == "supergroup"
84}
85
86// IsChannel returns if the Chat is a channel.
87func (c *Chat) IsChannel() bool {
88 return c.Type == "channel"
89}
90
91// Message is returned by almost every request, and contains data about
92// almost anything.
93type Message struct {
94 MessageID int `json:"message_id"`
95 From *User `json:"from"` // optional
96 Date int `json:"date"`
97 Chat *Chat `json:"chat"`
98 ForwardFrom *User `json:"forward_from"` // optional
99 ForwardFromChat *Chat `json:"forward_from_chat"` // optional
100 ForwardDate int `json:"forward_date"` // optional
101 ReplyToMessage *Message `json:"reply_to_message"` // optional
102 Text string `json:"text"` // optional
103 Entities *[]MessageEntity `json:"entities"` // optional
104 Audio *Audio `json:"audio"` // optional
105 Document *Document `json:"document"` // optional
106 Photo *[]PhotoSize `json:"photo"` // optional
107 Sticker *Sticker `json:"sticker"` // optional
108 Video *Video `json:"video"` // optional
109 Voice *Voice `json:"voice"` // optional
110 Caption string `json:"caption"` // optional
111 Contact *Contact `json:"contact"` // optional
112 Location *Location `json:"location"` // optional
113 Venue *Venue `json:"venue"` // optional
114 NewChatMember *User `json:"new_chat_member"` // optional
115 LeftChatMember *User `json:"left_chat_member"` // optional
116 NewChatTitle string `json:"new_chat_title"` // optional
117 NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
118 DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
119 GroupChatCreated bool `json:"group_chat_created"` // optional
120 SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
121 ChannelChatCreated bool `json:"channel_chat_created"` // optional
122 MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
123 MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
124 PinnedMessage *Message `json:"pinned_message"` // optional
125}
126
127// Time converts the message timestamp into a Time.
128func (m *Message) Time() time.Time {
129 return time.Unix(int64(m.Date), 0)
130}
131
132// IsCommand returns true if message starts with '/'.
133func (m *Message) IsCommand() bool {
134 return m.Text != "" && m.Text[0] == '/'
135}
136
137// Command checks if the message was a command and if it was, returns the
138// command. If the Message was not a command, it returns an empty string.
139//
140// If the command contains the at bot syntax, it removes the bot name.
141func (m *Message) Command() string {
142 if !m.IsCommand() {
143 return ""
144 }
145
146 command := strings.SplitN(m.Text, " ", 2)[0][1:]
147
148 if i := strings.Index(command, "@"); i != -1 {
149 command = command[:i]
150 }
151
152 return command
153}
154
155// CommandArguments checks if the message was a command and if it was,
156// returns all text after the command name. If the Message was not a
157// command, it returns an empty string.
158func (m *Message) CommandArguments() string {
159 if !m.IsCommand() {
160 return ""
161 }
162
163 split := strings.SplitN(m.Text, " ", 2)
164 if len(split) != 2 {
165 return ""
166 }
167
168 return strings.SplitN(m.Text, " ", 2)[1]
169}
170
171// MessageEntity contains information about data in a Message.
172type MessageEntity struct {
173 Type string `json:"type"`
174 Offset int `json:"offset"`
175 Length int `json:"length"`
176 URL string `json:"url"` // optional
177}
178
179// ParseURL attempts to parse a URL contained within a MessageEntity.
180func (entity MessageEntity) ParseURL() (*url.URL, error) {
181 if entity.URL == "" {
182 return nil, errors.New(ErrBadURL)
183 }
184
185 return url.Parse(entity.URL)
186}
187
188// PhotoSize contains information about photos.
189type PhotoSize struct {
190 FileID string `json:"file_id"`
191 Width int `json:"width"`
192 Height int `json:"height"`
193 FileSize int `json:"file_size"` // optional
194}
195
196// Audio contains information about audio.
197type Audio struct {
198 FileID string `json:"file_id"`
199 Duration int `json:"duration"`
200 Performer string `json:"performer"` // optional
201 Title string `json:"title"` // optional
202 MimeType string `json:"mime_type"` // optional
203 FileSize int `json:"file_size"` // optional
204}
205
206// Document contains information about a document.
207type Document struct {
208 FileID string `json:"file_id"`
209 Thumbnail *PhotoSize `json:"thumb"` // optional
210 FileName string `json:"file_name"` // optional
211 MimeType string `json:"mime_type"` // optional
212 FileSize int `json:"file_size"` // optional
213}
214
215// Sticker contains information about a sticker.
216type Sticker struct {
217 FileID string `json:"file_id"`
218 Width int `json:"width"`
219 Height int `json:"height"`
220 Thumbnail *PhotoSize `json:"thumb"` // optional
221 Emoji string `json:"emoji"` // optional
222 FileSize int `json:"file_size"` // optional
223}
224
225// Video contains information about a video.
226type Video struct {
227 FileID string `json:"file_id"`
228 Width int `json:"width"`
229 Height int `json:"height"`
230 Duration int `json:"duration"`
231 Thumbnail *PhotoSize `json:"thumb"` // optional
232 MimeType string `json:"mime_type"` // optional
233 FileSize int `json:"file_size"` // optional
234}
235
236// Voice contains information about a voice.
237type Voice struct {
238 FileID string `json:"file_id"`
239 Duration int `json:"duration"`
240 MimeType string `json:"mime_type"` // optional
241 FileSize int `json:"file_size"` // optional
242}
243
244// Contact contains information about a contact.
245//
246// Note that LastName and UserID may be empty.
247type Contact struct {
248 PhoneNumber string `json:"phone_number"`
249 FirstName string `json:"first_name"`
250 LastName string `json:"last_name"` // optional
251 UserID int `json:"user_id"` // optional
252}
253
254// Location contains information about a place.
255type Location struct {
256 Longitude float64 `json:"longitude"`
257 Latitude float64 `json:"latitude"`
258}
259
260// Venue contains information about a venue, including its Location.
261type Venue struct {
262 Location Location `json:"location"`
263 Title string `json:"title"`
264 Address string `json:"address"`
265 FoursquareID string `json:"foursquare_id"` // optional
266}
267
268// UserProfilePhotos contains a set of user profile photos.
269type UserProfilePhotos struct {
270 TotalCount int `json:"total_count"`
271 Photos [][]PhotoSize `json:"photos"`
272}
273
274// File contains information about a file to download from Telegram.
275type File struct {
276 FileID string `json:"file_id"`
277 FileSize int `json:"file_size"` // optional
278 FilePath string `json:"file_path"` // optional
279}
280
281// Link returns a full path to the download URL for a File.
282//
283// It requires the Bot Token to create the link.
284func (f *File) Link(token string) string {
285 return fmt.Sprintf(FileEndpoint, token, f.FilePath)
286}
287
288// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
289type ReplyKeyboardMarkup struct {
290 Keyboard [][]KeyboardButton `json:"keyboard"`
291 ResizeKeyboard bool `json:"resize_keyboard"` // optional
292 OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
293 Selective bool `json:"selective"` // optional
294}
295
296// KeyboardButton is a button within a custom keyboard.
297type KeyboardButton struct {
298 Text string `json:"text"`
299 RequestContact bool `json:"request_contact"`
300 RequestLocation bool `json:"request_location"`
301}
302
303// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
304type ReplyKeyboardHide struct {
305 HideKeyboard bool `json:"hide_keyboard"`
306 Selective bool `json:"selective"` // optional
307}
308
309// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
310type InlineKeyboardMarkup struct {
311 InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
312}
313
314// InlineKeyboardButton is a button within a custom keyboard for
315// inline query responses.
316//
317// Note that some values are references as even an empty string
318// will change behavior.
319type InlineKeyboardButton struct {
320 Text string `json:"text"`
321 URL *string `json:"url,omitempty"` // optional
322 CallbackData *string `json:"callback_data,omitempty"` // optional
323 SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
324}
325
326// CallbackQuery is data sent when a keyboard button with callback data
327// is clicked.
328type CallbackQuery struct {
329 ID string `json:"id"`
330 From *User `json:"from"`
331 Message *Message `json:"message"` // optional
332 InlineMessageID string `json:"inline_message_id"` // optional
333 Data string `json:"data"` // optional
334}
335
336// ForceReply allows the Bot to have users directly reply to it without
337// additional interaction.
338type ForceReply struct {
339 ForceReply bool `json:"force_reply"`
340 Selective bool `json:"selective"` // optional
341}
342
343// InlineQuery is a Query from Telegram for an inline request.
344type InlineQuery struct {
345 ID string `json:"id"`
346 From *User `json:"from"`
347 Location *Location `json:"location"` // optional
348 Query string `json:"query"`
349 Offset string `json:"offset"`
350}
351
352// InlineQueryResultArticle is an inline query response article.
353type InlineQueryResultArticle struct {
354 Type string `json:"type"` // required
355 ID string `json:"id"` // required
356 Title string `json:"title"` // required
357 InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
358 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
359 URL string `json:"url"`
360 HideURL bool `json:"hide_url"`
361 Description string `json:"description"`
362 ThumbURL string `json:"thumb_url"`
363 ThumbWidth int `json:"thumb_width"`
364 ThumbHeight int `json:"thumb_height"`
365}
366
367// InlineQueryResultPhoto is an inline query response photo.
368type InlineQueryResultPhoto struct {
369 Type string `json:"type"` // required
370 ID string `json:"id"` // required
371 URL string `json:"photo_url"` // required
372 MimeType string `json:"mime_type"`
373 Width int `json:"photo_width"`
374 Height int `json:"photo_height"`
375 ThumbURL string `json:"thumb_url"`
376 Title string `json:"title"`
377 Description string `json:"description"`
378 Caption string `json:"caption"`
379 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
380 InputMessageContent interface{} `json:"input_message_content,omitempty"`
381}
382
383// InlineQueryResultGIF is an inline query response GIF.
384type InlineQueryResultGIF struct {
385 Type string `json:"type"` // required
386 ID string `json:"id"` // required
387 URL string `json:"gif_url"` // required
388 Width int `json:"gif_width"`
389 Height int `json:"gif_height"`
390 ThumbURL string `json:"thumb_url"`
391 Title string `json:"title"`
392 Caption string `json:"caption"`
393 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
394 InputMessageContent interface{} `json:"input_message_content,omitempty"`
395}
396
397// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
398type InlineQueryResultMPEG4GIF struct {
399 Type string `json:"type"` // required
400 ID string `json:"id"` // required
401 URL string `json:"mpeg4_url"` // required
402 Width int `json:"mpeg4_width"`
403 Height int `json:"mpeg4_height"`
404 ThumbURL string `json:"thumb_url"`
405 Title string `json:"title"`
406 Caption string `json:"caption"`
407 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
408 InputMessageContent interface{} `json:"input_message_content,omitempty"`
409}
410
411// InlineQueryResultVideo is an inline query response video.
412type InlineQueryResultVideo struct {
413 Type string `json:"type"` // required
414 ID string `json:"id"` // required
415 URL string `json:"video_url"` // required
416 MimeType string `json:"mime_type"` // required
417 ThumbURL string `json:"thumb_url"`
418 Title string `json:"title"`
419 Caption string `json:"caption"`
420 Width int `json:"video_width"`
421 Height int `json:"video_height"`
422 Duration int `json:"video_duration"`
423 Description string `json:"description"`
424 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
425 InputMessageContent interface{} `json:"input_message_content,omitempty"`
426}
427
428// InlineQueryResultAudio is an inline query response audio.
429type InlineQueryResultAudio struct {
430 Type string `json:"type"` // required
431 ID string `json:"id"` // required
432 URL string `json:"audio_url"` // required
433 Title string `json:"title"` // required
434 Performer string `json:"performer"`
435 Duration int `json:"audio_duration"`
436 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
437 InputMessageContent interface{} `json:"input_message_content,omitempty"`
438}
439
440// InlineQueryResultVoice is an inline query response voice.
441type InlineQueryResultVoice struct {
442 Type string `json:"type"` // required
443 ID string `json:"id"` // required
444 URL string `json:"voice_url"` // required
445 Title string `json:"title"` // required
446 Duration int `json:"voice_duration"`
447 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
448 InputMessageContent interface{} `json:"input_message_content,omitempty"`
449}
450
451// InlineQueryResultDocument is an inline query response document.
452type InlineQueryResultDocument struct {
453 Type string `json:"type"` // required
454 ID string `json:"id"` // required
455 Title string `json:"title"` // required
456 Caption string `json:"caption"`
457 URL string `json:"document_url"` // required
458 MimeType string `json:"mime_type"` // required
459 Description string `json:"description"`
460 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
461 InputMessageContent interface{} `json:"input_message_content,omitempty"`
462 ThumbURL string `json:"thumb_url"`
463 ThumbWidth int `json:"thumb_width"`
464 ThumbHeight int `json:"thumb_height"`
465}
466
467// InlineQueryResultLocation is an inline query response location.
468type InlineQueryResultLocation struct {
469 Type string `json:"type"` // required
470 ID string `json:"id"` // required
471 Latitude float64 `json:"latitude"` // required
472 Longitude float64 `json:"longitude"` // required
473 Title string `json:"title"` // required
474 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
475 InputMessageContent interface{} `json:"input_message_content,omitempty"`
476 ThumbURL string `json:"thumb_url"`
477 ThumbWidth int `json:"thumb_width"`
478 ThumbHeight int `json:"thumb_height"`
479}
480
481// ChosenInlineResult is an inline query result chosen by a User
482type ChosenInlineResult struct {
483 ResultID string `json:"result_id"`
484 From *User `json:"from"`
485 Location *Location `json:"location"`
486 InlineMessageID string `json:"inline_message_id"`
487 Query string `json:"query"`
488}
489
490// InputTextMessageContent contains text for displaying
491// as an inline query result.
492type InputTextMessageContent struct {
493 Text string `json:"message_text"`
494 ParseMode string `json:"parse_mode"`
495 DisableWebPagePreview bool `json:"disable_web_page_preview"`
496}
497
498// InputLocationMessageContent contains a location for displaying
499// as an inline query result.
500type InputLocationMessageContent struct {
501 Latitude float64 `json:"latitude"`
502 Longitude float64 `json:"longitude"`
503}
504
505// InputVenueMessageContent contains a venue for displaying
506// as an inline query result.
507type InputVenueMessageContent struct {
508 Latitude float64 `json:"latitude"`
509 Longitude float64 `json:"longitude"`
510 Title string `json:"title"`
511 Address string `json:"address"`
512 FoursquareID string `json:"foursquare_id"`
513}
514
515// InputContactMessageContent contains a contact for displaying
516// as an inline query result.
517type InputContactMessageContent struct {
518 PhoneNumber string `json:"phone_number"`
519 FirstName string `json:"first_name"`
520 LastName string `json:"last_name"`
521}