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