From 60f09e940a6d31efc90cc1777083425befe48aea Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Thu, 5 Feb 2026 12:16:25 +0300 Subject: [PATCH 01/16] v0.4.0 --- api.go | 31 ++++-- bot.go | 16 +++- handler.go | 12 +++ keyboard.go | 4 +- methods.go | 251 ++++++++++++++++++++++++++++++++++++------------- msg_context.go | 36 +++---- plugins.go | 2 +- types.go | 36 ++++++- uploader.go | 24 +++-- utils.go | 11 +++ version.go | 6 +- 11 files changed, 319 insertions(+), 110 deletions(-) diff --git a/api.go b/api.go index aa9983e..31de0b6 100644 --- a/api.go +++ b/api.go @@ -7,8 +7,27 @@ import ( "io" "net/http" "strings" + + "git.nix13.pw/scuroneko/slog" ) +type Api struct { + token string + logger *slog.Logger +} + +func NewAPI(token string) *Api { + l := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("API") + l.AddWriter(l.CreateJsonStdoutWriter()) + return &Api{ + token: token, + logger: l, + } +} +func (api *Api) CloseApi() { + api.logger.Close() +} + type ApiResponse[R any] struct { Ok bool `json:"ok"` Description string `json:"description,omitempty"` @@ -24,21 +43,21 @@ type TelegramRequest[R, P any] struct { func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] { return TelegramRequest[R, P]{method: method, params: params} } -func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) { +func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) { var buf bytes.Buffer err := json.NewEncoder(&buf).Encode(r.params) if err != nil { return nil, err } - if bot.requestLogger != nil { - bot.requestLogger.Debugln(strings.ReplaceAll(fmt.Sprintf( + if api.logger != nil { + api.logger.Debugln(strings.ReplaceAll(fmt.Sprintf( "POST https://api.telegram.org/bot%s/%s %s", "", r.method, buf.String(), ), "\n", "")) } - req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, r.method), "application/json", &buf) + req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method), "application/json", &buf) if err != nil { return nil, err } @@ -48,8 +67,8 @@ func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) { return nil, err } - if bot.requestLogger != nil { - bot.requestLogger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) + if api.logger != nil { + api.logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) } response := new(ApiResponse[R]) diff --git a/bot.go b/bot.go index 9295a9c..f17db42 100644 --- a/bot.go +++ b/bot.go @@ -37,6 +37,9 @@ type Bot struct { runners []Runner dbContext *DatabaseContext + api *Api + + dbWriterRequested extypes.Slice[*slog.Logger] updateOffset int updateTypes []string @@ -75,12 +78,14 @@ func LoadPrefixesFromEnv() []string { } func NewBot(settings *BotSettings) *Bot { updateQueue := extypes.CreateQueue[*Update](256) + api := NewAPI(settings.Token) bot := &Bot{ updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s", prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0), - updateQueue: updateQueue, - token: settings.Token, + updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0), + token: settings.Token, } + bot.dbWriterRequested = bot.dbWriterRequested.Push(api.logger) if len(settings.ErrorTemplate) > 0 { bot.errorTemplate = settings.ErrorTemplate @@ -118,7 +123,7 @@ func NewBot(settings *BotSettings) *Bot { } } - u, err := bot.GetMe() + u, err := api.GetMe() if err != nil { bot.logger.Fatal(err) } @@ -150,6 +155,9 @@ func (b *Bot) AddDatabaseLogger(writer func(db *DatabaseContext) slog.LoggerWrit if b.requestLogger != nil { b.requestLogger.AddWriter(w) } + for _, l := range b.dbWriterRequested { + l.AddWriter(w) + } return b } @@ -251,7 +259,7 @@ func (b *Bot) Run() { continue } - ctx := &MsgContext{Bot: b, Update: u} + ctx := &MsgContext{Bot: b, Update: u, Api: b.api} for _, middleware := range b.middlewares { middleware.Execute(ctx, b.dbContext) } diff --git a/handler.go b/handler.go index c2f8877..487843d 100644 --- a/handler.go +++ b/handler.go @@ -35,6 +35,18 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { if !strings.HasPrefix(text, cmd) { continue } + requestParts := strings.Split(text, " ") + cmdParts := strings.Split(cmd, " ") + isValid := true + for i, part := range cmdParts { + if part != requestParts[i] { + isValid = false + break + } + } + if !isValid { + continue + } ctx.Text = strings.TrimSpace(text[len(cmd):]) ctx.Args = strings.Split(ctx.Text, " ") diff --git a/keyboard.go b/keyboard.go index bdb9e35..b023332 100644 --- a/keyboard.go +++ b/keyboard.go @@ -41,11 +41,11 @@ func (in *InlineKeyboard) AddLine() *InlineKeyboard { in.CurrentLine = make([]InlineKeyboardButton, 0) return in } -func (in *InlineKeyboard) Get() InlineKeyboardMarkup { +func (in *InlineKeyboard) Get() *InlineKeyboardMarkup { if len(in.CurrentLine) > 0 { in.Lines = append(in.Lines, in.CurrentLine) } - return InlineKeyboardMarkup{ + return &InlineKeyboardMarkup{ InlineKeyboard: in.Lines, } } diff --git a/methods.go b/methods.go index 81ef1b6..2dc3372 100644 --- a/methods.go +++ b/methods.go @@ -23,7 +23,7 @@ func (b *Bot) Updates() ([]*Update, error) { } req := NewRequest[[]*Update]("getUpdates", params) - res, err := req.Do(b) + res, err := req.Do(b.api) if err != nil { return []*Update{}, err } @@ -47,30 +47,143 @@ func (b *Bot) Updates() ([]*Update, error) { return updates, err } -func (b *Bot) GetMe() (*User, error) { +func (api *Api) GetMe() (*User, error) { req := NewRequest[User, EmptyParams]("getMe", NoParams) - return req.Do(b) + return req.Do(api) +} +func (api *Api) LogOut() (bool, error) { + req := NewRequest[bool, EmptyParams]("logOut", NoParams) + res, err := req.Do(api) + if err != nil { + return false, err + } + return *res, nil +} +func (api *Api) Close() (bool, error) { + req := NewRequest[bool, EmptyParams]("close", NoParams) + res, err := req.Do(api) + if err != nil { + return false, err + } + return *res, nil } type SendMessageP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Text string `json:"text"` - Entities []*MessageEntity `json:"entities,omitempty"` - LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Entities []*MessageEntity `json:"entities,omitempty"` + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) SendMessage(params *SendMessageP) (*Message, error) { +func (api *Api) SendMessage(params *SendMessageP) (*Message, error) { req := NewRequest[Message, SendMessageP]("sendMessage", *params) - return req.Do(b) + return req.Do(api) +} + +type ForwardMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + MessageID int `json:"message_id,omitempty"` + FromChatID int `json:"from_chat_id,omitempty"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + + MessageEffectID string `json:"message_effect_id,omitempty"` + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` +} + +func (api *Api) ForwardMessage(params ForwardMessageP) (*Message, error) { + req := NewRequest[Message]("forwardMessage", params) + return req.Do(api) +} + +type ForwardMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` +} + +func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) { + req := NewRequest[[]int]("forwardMessages", params) + res, err := req.Do(api) + if err != nil { + return []int{}, err + } + return *res, nil +} + +type CopyMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id"` + MessageID int `json:"message_id"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) CopyMessage(params CopyMessageP) (int, error) { + req := NewRequest[int]("copyMessage", params) + res, err := req.Do(api) + if err != nil { + return 0, err + } + return *res, nil +} + +type CopyMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + RemoveCaption bool `json:"remove_caption,omitempty"` +} + +func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) { + req := NewRequest[[]int]("copyMessages", params) + res, err := req.Do(api) + if err != nil { + return []int{}, err + } + return *res, nil } type SendPhotoBaseP struct { @@ -89,55 +202,61 @@ type SendPhotoBaseP struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } type SendPhotoP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` - Photo string `json:"photo"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Photo string `json:"photo"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) SendPhoto(params *SendPhotoP) (*Message, error) { +func (api *Api) SendPhoto(params *SendPhotoP) (*Message, error) { req := NewRequest[Message]("sendPhoto", params) - return req.Do(b) + return req.Do(api) } type EditMessageTextP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Text string `json:"text"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) EditMessageText(params *EditMessageTextP) (*Message, error) { +func (api *Api) EditMessageText(params *EditMessageTextP) (*Message, error) { req := NewRequest[Message]("editMessageText", params) - return req.Do(b) + return req.Do(api) } type EditMessageCaptionP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Caption string `json:"caption"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Caption string `json:"caption"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) { +func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) { req := NewRequest[Message]("editMessageCaption", params) - return req.Do(b) + return req.Do(api) } type DeleteMessageP struct { @@ -145,9 +264,9 @@ type DeleteMessageP struct { MessageID int `json:"message_id"` } -func (b *Bot) DeleteMessage(params *DeleteMessageP) (bool, error) { +func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) { req := NewRequest[bool]("deleteMessage", params) - ok, err := req.Do(b) + ok, err := req.Do(api) if err != nil { return false, err } @@ -162,9 +281,9 @@ type AnswerCallbackQueryP struct { CacheTime int `json:"cache_time,omitempty"` } -func (b *Bot) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { +func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { req := NewRequest[bool]("answerCallbackQuery", params) - ok, err := req.Do(b) + ok, err := req.Do(api) if err != nil { return false, err } @@ -175,9 +294,9 @@ type GetFileP struct { FileId string `json:"file_id"` } -func (b *Bot) GetFile(params *GetFileP) (*File, error) { +func (api *Api) GetFile(params *GetFileP) (*File, error) { req := NewRequest[File]("getFile", params) - return req.Do(b) + return req.Do(api) } type SendChatActionP struct { @@ -187,9 +306,9 @@ type SendChatActionP struct { Action ChatActions `json:"action"` } -func (b *Bot) SendChatAction(params SendChatActionP) (bool, error) { +func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { req := NewRequest[bool]("sendChatAction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -206,9 +325,9 @@ type SetMessageReactionEmojiP struct { Reaction []ReactionTypeEmoji `json:"reaction"` } -func (b *Bot) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) { +func (api *Api) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -220,9 +339,9 @@ type SetMessageReactionCustomEmojiP struct { Reaction []ReactionTypeCustomEmoji `json:"reaction"` } -func (b *Bot) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) { +func (api *Api) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -233,9 +352,9 @@ type SetMessageReactionPaidP struct { SetMessageReactionP } -func (b *Bot) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) { +func (api *Api) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } diff --git a/msg_context.go b/msg_context.go index e1d92bc..fa9f2c0 100644 --- a/msg_context.go +++ b/msg_context.go @@ -3,7 +3,9 @@ package laniakea import "fmt" type MsgContext struct { - Bot *Bot + Bot *Bot + Api *Api + Msg *Message Update *Update From *User @@ -33,9 +35,9 @@ func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard if keyboard != nil { params.ReplyMarkup = keyboard.Get() } - msg, err := ctx.Bot.EditMessageText(params) + msg, err := ctx.Api.EditMessageText(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return nil } return &AnswerMessage{ @@ -47,7 +49,7 @@ func (m *AnswerMessage) Edit(text string) *AnswerMessage { } func (ctx *MsgContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage { if ctx.CallbackMsgId == 0 { - ctx.Bot.logger.Errorln("Can't edit non-callback update message") + ctx.Api.logger.Errorln("Can't edit non-callback update message") return nil } @@ -67,9 +69,9 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo if kb != nil { params.ReplyMarkup = kb.Get() } - msg, err := ctx.Bot.EditMessageCaption(params) + msg, err := ctx.Api.EditMessageCaption(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } return &AnswerMessage{ MessageID: msg.MessageID, ctx: ctx, Text: text, IsMedia: true, @@ -77,7 +79,7 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo } func (m *AnswerMessage) EditCaption(text string) *AnswerMessage { if m.MessageID == 0 { - m.ctx.Bot.logger.Errorln("Can't edit caption message, message id is zero") + m.ctx.Api.logger.Errorln("Can't edit caption message, message id is zero") return m } return m.ctx.editPhotoText(m.MessageID, text, nil) @@ -96,9 +98,9 @@ func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMess params.ReplyMarkup = keyboard.Get() } - msg, err := ctx.Bot.SendMessage(params) + msg, err := ctx.Api.SendMessage(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return nil } return &AnswerMessage{ @@ -125,9 +127,9 @@ func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *An if kb != nil { params.ReplyMarkup = kb.Get() } - msg, err := ctx.Bot.SendPhoto(params) + msg, err := ctx.Api.SendPhoto(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return &AnswerMessage{ ctx: ctx, Text: text, IsMedia: true, } @@ -144,12 +146,12 @@ func (ctx *MsgContext) AnswerPhotoKeyboard(photoId, text string, kb *InlineKeybo } func (ctx *MsgContext) delete(messageId int) { - _, err := ctx.Bot.DeleteMessage(&DeleteMessageP{ + _, err := ctx.Api.DeleteMessage(&DeleteMessageP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } func (m *AnswerMessage) Delete() { @@ -163,12 +165,12 @@ func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) { if len(ctx.CallbackQueryId) == 0 { return } - _, err := ctx.Bot.AnswerCallbackQuery(&AnswerCallbackQueryP{ + _, err := ctx.Api.AnswerCallbackQuery(&AnswerCallbackQueryP{ CallbackQueryID: ctx.CallbackQueryId, Text: text, ShowAlert: showAlert, URL: url, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } func (ctx *MsgContext) AnswerCbQuery() { @@ -185,11 +187,11 @@ func (ctx *MsgContext) AnswerCbQueryUrl(u string) { } func (ctx *MsgContext) SendAction(action ChatActions) { - _, err := ctx.Bot.SendChatAction(SendChatActionP{ + _, err := ctx.Api.SendChatAction(SendChatActionP{ ChatID: ctx.Msg.Chat.ID, Action: action, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } diff --git a/plugins.go b/plugins.go index 86b5e96..945bbc3 100644 --- a/plugins.go +++ b/plugins.go @@ -58,7 +58,7 @@ func (p *PluginBuilder) Middleware(middleware *PluginMiddleware) *PluginBuilder func (p *PluginBuilder) Build() Plugin { if len(p.commands) == 0 && len(p.payloads) == 0 { - log.Println("no command or payloads") + log.Printf("no command or payloads for %s", p.name) } return Plugin{ Name: p.name, diff --git a/types.go b/types.go index 974f144..50f652e 100644 --- a/types.go +++ b/types.go @@ -83,13 +83,15 @@ type MessageEntity struct { } type ReplyParameters struct { - MessageID int `json:"message_id"` - ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id"` + ChatID int `json:"chat_id,omitempty"` + AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"` Quote string `json:"quote,omitempty"` QuoteParsingMode string `json:"quote_parsing_mode,omitempty"` QuoteEntities []*MessageEntity `json:"quote_entities,omitempty"` - QuotePosition int `json:"quote_postigin,omitempty"` + QuotePosition int `json:"quote_position,omitempty"` + ChecklistTaskID int `json:"checklist_task_id,omitempty"` } type PhotoSize struct { @@ -108,6 +110,20 @@ type LinkPreviewOptions struct { ShowAboveText bool `json:"show_above_text,omitempty"` } +type ReplyMarkup struct { + InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` + + Keyboard [][]int `json:"keyboard,omitempty"` + IsPersistent bool `json:"is_persistent,omitempty"` + ResizeKeyboard bool `json:"resize_keyboard,omitempty"` + OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"` + InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` + Selective bool `json:"selective,omitempty"` + + RemoveKeyboard bool `json:"remove_keyboard,omitempty"` + + ForceReply bool `json:"force_reply,omitempty"` +} type InlineKeyboardMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` } @@ -194,3 +210,17 @@ const ( ChatActionFindLocation ChatActions = "find_location" ChatActionUploadVideoNone ChatActions = "upload_video_none" ) + +type SuggestedPostPrice struct { + Currency string `json:"currency"` + Amount int `json:"amount"` +} +type SuggestedPostInfo struct { + State string `json:"state"` //State of the suggested post. Currently, it can be one of “pending”, “approved”, “declined”. + Price SuggestedPostPrice `json:"price"` + SendDate int `json:"send_date"` +} +type SuggestedPostParameters struct { + Price SuggestedPostPrice `json:"price"` + SendDate int `json:"send_date"` +} diff --git a/uploader.go b/uploader.go index def36ce..087a4f2 100644 --- a/uploader.go +++ b/uploader.go @@ -8,14 +8,22 @@ import ( "mime/multipart" "net/http" "path/filepath" + + "git.nix13.pw/scuroneko/slog" ) type Uploader struct { - bot *Bot + api *Api + logger *slog.Logger } -func NewUploader(bot *Bot) *Uploader { - return &Uploader{bot: bot} +func NewUploader(api *Api) *Uploader { + logger := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("UPLOADER") + logger.AddWriter(logger.CreateJsonStdoutWriter()) + return &Uploader{api, logger} +} +func (u *Uploader) Close() { + u.logger.Close() } type UploaderFileType string @@ -56,8 +64,8 @@ func NewUploaderRequest[R, P any](method string, file UploaderFile, params P) Up return UploaderRequest[R, P]{method, file, params} } -func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { - url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, u.method) +func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) { + url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method) buf := bytes.NewBuffer(nil) w := multipart.NewWriter(buf) @@ -87,7 +95,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { return nil, err } req.Header.Set("Content-Type", w.FormDataContentType()) - bot.logger.Debugln("UPLOADER REQ", u.method) + up.logger.Debugln("UPLOADER REQ", u.method) res, err := http.DefaultClient.Do(req) if err != nil { return nil, err @@ -98,7 +106,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { if err != nil { return nil, err } - bot.logger.Debugln("UPLOADER RES", u.method, string(body)) + up.logger.Debugln("UPLOADER RES", u.method, string(body)) if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body)) } @@ -116,7 +124,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) { req := NewUploaderRequest[Message]("sendPhoto", file, params) - return req.Do(u.bot) + return req.Do(u) } func uploaderTypeByExt(filename string) UploaderFileType { diff --git a/utils.go b/utils.go index 5bfad8d..5b0f372 100644 --- a/utils.go +++ b/utils.go @@ -3,9 +3,20 @@ package laniakea import ( "encoding/json" "fmt" + "os" "strings" + + "git.nix13.pw/scuroneko/slog" ) +func GetLoggerLevel() slog.LogLevel { + level := slog.FATAL + if os.Getenv("DEBUG") == "true" { + level = slog.DEBUG + } + return level +} + // MapToStruct unsafe function func MapToStruct(m map[string]any, s any) error { data, err := json.Marshal(m) diff --git a/version.go b/version.go index 2661f98..8d2c2b6 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.3.9" + VersionString = "0.4.0" VersionMajor = 0 - VersionMinor = 3 - VersionPatch = 9 + VersionMinor = 4 + VersionPatch = 0 ) -- 2.53.0 From 9d18bef97eca7de17aa71c5fd92bda5e8c310797 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 14:14:17 +0300 Subject: [PATCH 02/16] v0.4.1; bot api v9.4 --- api.go | 32 ++++++++++--------------- go.mod | 6 ++--- go.sum | 8 +++---- keyboard.go | 68 +++++++++++++++++++++++++++++++++++++++++++--------- methods.go | 14 +++++------ multipart.go | 1 - types.go | 9 ++++--- uploader.go | 4 ++-- version.go | 4 ++-- 9 files changed, 92 insertions(+), 54 deletions(-) diff --git a/api.go b/api.go index 31de0b6..6fa7458 100644 --- a/api.go +++ b/api.go @@ -19,13 +19,10 @@ type Api struct { func NewAPI(token string) *Api { l := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("API") l.AddWriter(l.CreateJsonStdoutWriter()) - return &Api{ - token: token, - logger: l, - } + return &Api{token, l} } -func (api *Api) CloseApi() { - api.logger.Close() +func (api *Api) CloseApi() error { + return api.logger.Close() } type ApiResponse[R any] struct { @@ -44,25 +41,25 @@ func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] { return TelegramRequest[R, P]{method: method, params: params} } func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) { - var buf bytes.Buffer - err := json.NewEncoder(&buf).Encode(r.params) + buf := bytes.NewBuffer(nil) + err := json.NewEncoder(buf).Encode(r.params) if err != nil { return nil, err } + u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method) if api.logger != nil { api.logger.Debugln(strings.ReplaceAll(fmt.Sprintf( - "POST https://api.telegram.org/bot%s/%s %s", - "", r.method, buf.String(), - ), "\n", "")) + "POST %s %s", u, buf.String(), + ), api.token, "")) } - req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method), "application/json", &buf) + res, err := http.Post(u, "application/json", buf) if err != nil { return nil, err } - defer req.Body.Close() - data, err := io.ReadAll(req.Body) + defer res.Body.Close() + data, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -84,13 +81,8 @@ func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) { } func (b *Bot) GetFileByLink(link string) ([]byte, error) { - c := http.DefaultClient u := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", b.token, link) - req, err := http.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - res, err := c.Do(req) + res, err := http.Get(u) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index bf2cc14..47a6504 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module git.nix13.pw/scuroneko/laniakea -go 1.25.6 +go 1.25 require ( - git.nix13.pw/scuroneko/extypes v1.0.2 + git.nix13.pw/scuroneko/extypes v1.1.0 git.nix13.pw/scuroneko/slog v1.0.2 github.com/redis/go-redis/v9 v9.17.3 github.com/vinovest/sqlx v1.7.1 @@ -14,7 +14,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.18.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/muir/sqltoken v0.2.1 // indirect diff --git a/go.sum b/go.sum index e737cc0..24e8718 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -git.nix13.pw/scuroneko/extypes v1.0.2 h1:Qz1InLccaB9crXY33oGrSetPHePKfQAUqW/p/iYXmJk= -git.nix13.pw/scuroneko/extypes v1.0.2/go.mod h1:uZVs8Yo3RrYAG9dMad6qR6lsYY67t+459D9c65QAYAw= +git.nix13.pw/scuroneko/extypes v1.1.0 h1:kdAraybAqQgVhArVkVfrIi7KVEX8HgTr8mzbIZAAAqg= +git.nix13.pw/scuroneko/extypes v1.1.0/go.mod h1:uZVs8Yo3RrYAG9dMad6qR6lsYY67t+459D9c65QAYAw= git.nix13.pw/scuroneko/slog v1.0.2 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g= git.nix13.pw/scuroneko/slog v1.0.2/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= @@ -20,8 +20,8 @@ github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1 github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= diff --git a/keyboard.go b/keyboard.go index b023332..8173fe6 100644 --- a/keyboard.go +++ b/keyboard.go @@ -3,51 +3,97 @@ package laniakea import ( "encoding/json" "fmt" + + "git.nix13.pw/scuroneko/extypes" ) +type InlineKbButtonBuilder struct { + text string + iconCustomEmojiID string + style InlineKeyboardButtonStyle + url string + callbackData string +} + +func NewInlineKbButton(text string) InlineKbButtonBuilder { + return InlineKbButtonBuilder{text: text} +} +func (b InlineKbButtonBuilder) SetIconCustomEmojiId(id string) InlineKbButtonBuilder { + b.iconCustomEmojiID = id + return b +} +func (b InlineKbButtonBuilder) SetStyle(style InlineKeyboardButtonStyle) InlineKbButtonBuilder { + b.style = style + return b +} +func (b InlineKbButtonBuilder) SetUrl(url string) InlineKbButtonBuilder { + b.url = url + return b +} +func (b InlineKbButtonBuilder) SetCallbackData(data *CallbackData) InlineKbButtonBuilder { + b.callbackData = data.ToJson() + return b +} + +func (b InlineKbButtonBuilder) build() InlineKeyboardButton { + return InlineKeyboardButton{ + Text: b.text, + URL: b.url, + Style: b.style, + IconCustomEmojiID: b.iconCustomEmojiID, + CallbackData: b.callbackData, + } +} + type InlineKeyboard struct { - CurrentLine []InlineKeyboardButton + CurrentLine extypes.Slice[InlineKeyboardButton] Lines [][]InlineKeyboardButton maxRow int } func NewInlineKeyboard(maxRow int) *InlineKeyboard { return &InlineKeyboard{ - CurrentLine: make([]InlineKeyboardButton, 0), + CurrentLine: make(extypes.Slice[InlineKeyboardButton], 0), Lines: make([][]InlineKeyboardButton, 0), maxRow: maxRow, } } func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard { - if len(in.CurrentLine) == in.maxRow { + if in.CurrentLine.Len() == in.maxRow { in.AddLine() } - in.CurrentLine = append(in.CurrentLine, button) + in.CurrentLine = in.CurrentLine.Push(button) return in } func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard { return in.append(InlineKeyboardButton{Text: text, URL: url}) } func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any) *InlineKeyboard { - return in.append(InlineKeyboardButton{Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson()}) + return in.append(InlineKeyboardButton{ + Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson(), + }) +} +func (in *InlineKeyboard) AddCustomButton(button InlineKeyboardButton) *InlineKeyboard { + return in.append(button) +} +func (in *InlineKeyboard) AddButton(b InlineKbButtonBuilder) *InlineKeyboard { + return in.append(b.build()) } func (in *InlineKeyboard) AddLine() *InlineKeyboard { - if len(in.CurrentLine) == 0 { + if in.CurrentLine.Len() == 0 { return in } in.Lines = append(in.Lines, in.CurrentLine) - in.CurrentLine = make([]InlineKeyboardButton, 0) + in.CurrentLine = make(extypes.Slice[InlineKeyboardButton], 0) return in } func (in *InlineKeyboard) Get() *InlineKeyboardMarkup { - if len(in.CurrentLine) > 0 { + if in.CurrentLine.Len() > 0 { in.Lines = append(in.Lines, in.CurrentLine) } - return &InlineKeyboardMarkup{ - InlineKeyboard: in.Lines, - } + return &InlineKeyboardMarkup{InlineKeyboard: in.Lines} } type CallbackData struct { diff --git a/methods.go b/methods.go index 2dc3372..48a35ef 100644 --- a/methods.go +++ b/methods.go @@ -2,7 +2,6 @@ package laniakea import ( "encoding/json" - "fmt" ) type EmptyParams struct{} @@ -25,26 +24,25 @@ func (b *Bot) Updates() ([]*Update, error) { req := NewRequest[[]*Update]("getUpdates", params) res, err := req.Do(b.api) if err != nil { - return []*Update{}, err + return nil, err } - updates := *res - for _, u := range updates { + for _, u := range *res { b.updateOffset = u.UpdateID + 1 err = b.updateQueue.Enqueue(u) if err != nil { - return updates, err + return nil, err } - if b.debug && b.requestLogger != nil { + if b.requestLogger != nil { j, err := json.Marshal(u) if err != nil { b.logger.Error(err) } - b.requestLogger.Debugln(fmt.Sprintf("UPDATE %s", j)) + b.requestLogger.Debugf("UPDATE %s\n", j) } } - return updates, err + return *res, err } func (api *Api) GetMe() (*User, error) { diff --git a/multipart.go b/multipart.go index e928fc3..5fc75df 100644 --- a/multipart.go +++ b/multipart.go @@ -78,7 +78,6 @@ func Encode[T any](w *multipart.Writer, req T) error { if err == nil { _, err = fw.Write([]byte(strconv.FormatBool(field.Bool()))) } - case reflect.Slice: if field.Type().Elem().Kind() == reflect.Uint8 && !field.IsNil() { filename := fieldType.Tag.Get("filename") diff --git a/types.go b/types.go index 50f652e..1d43b49 100644 --- a/types.go +++ b/types.go @@ -128,10 +128,13 @@ type InlineKeyboardMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` } +type InlineKeyboardButtonStyle string type InlineKeyboardButton struct { - Text string `json:"text"` - URL string `json:"url,omitempty"` - CallbackData string `json:"callback_data,omitempty"` + Text string `json:"text"` + URL string `json:"url,omitempty"` + CallbackData string `json:"callback_data,omitempty"` + Style InlineKeyboardButtonStyle `json:"style,omitempty"` + IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` } type ReplyKeyboardMarkup struct { diff --git a/uploader.go b/uploader.go index 087a4f2..8e76341 100644 --- a/uploader.go +++ b/uploader.go @@ -22,8 +22,8 @@ func NewUploader(api *Api) *Uploader { logger.AddWriter(logger.CreateJsonStdoutWriter()) return &Uploader{api, logger} } -func (u *Uploader) Close() { - u.logger.Close() +func (u *Uploader) Close() error { + return u.logger.Close() } type UploaderFileType string diff --git a/version.go b/version.go index 8d2c2b6..8f51651 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.4.0" + VersionString = "0.4.1" VersionMajor = 0 VersionMinor = 4 - VersionPatch = 0 + VersionPatch = 1 ) -- 2.53.0 From 2cc2f96f02d7c52f885f797eae24c0c88ffe6b46 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 14:17:44 +0300 Subject: [PATCH 03/16] v0.4.2 --- keyboard.go | 10 +++++----- version.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/keyboard.go b/keyboard.go index 8173fe6..062ddae 100644 --- a/keyboard.go +++ b/keyboard.go @@ -30,8 +30,8 @@ func (b InlineKbButtonBuilder) SetUrl(url string) InlineKbButtonBuilder { b.url = url return b } -func (b InlineKbButtonBuilder) SetCallbackData(data *CallbackData) InlineKbButtonBuilder { - b.callbackData = data.ToJson() +func (b InlineKbButtonBuilder) SetCallbackData(cmd string, args ...any) InlineKbButtonBuilder { + b.callbackData = NewCallbackData(cmd, args...).ToJson() return b } @@ -74,12 +74,12 @@ func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson(), }) } -func (in *InlineKeyboard) AddCustomButton(button InlineKeyboardButton) *InlineKeyboard { - return in.append(button) -} func (in *InlineKeyboard) AddButton(b InlineKbButtonBuilder) *InlineKeyboard { return in.append(b.build()) } +func (in *InlineKeyboard) AddCustomButton(button InlineKeyboardButton) *InlineKeyboard { + return in.append(button) +} func (in *InlineKeyboard) AddLine() *InlineKeyboard { if in.CurrentLine.Len() == 0 { diff --git a/version.go b/version.go index 8f51651..95681a0 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.4.1" + VersionString = "0.4.2" VersionMajor = 0 VersionMinor = 4 - VersionPatch = 1 + VersionPatch = 2 ) -- 2.53.0 From 83dca1ab394645edfe98922b912865ad9de49ff0 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 14:27:24 +0300 Subject: [PATCH 04/16] v0.4.2.1 --- keyboard.go | 10 ++++++++-- types.go | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/keyboard.go b/keyboard.go index 062ddae..128c40e 100644 --- a/keyboard.go +++ b/keyboard.go @@ -7,10 +7,16 @@ import ( "git.nix13.pw/scuroneko/extypes" ) +const ( + ButtonStyleDanger KeyboardButtonStyle = "danger" + ButtonStyleSuccess KeyboardButtonStyle = "success" + ButtonStylePrimary KeyboardButtonStyle = "primary" +) + type InlineKbButtonBuilder struct { text string iconCustomEmojiID string - style InlineKeyboardButtonStyle + style KeyboardButtonStyle url string callbackData string } @@ -22,7 +28,7 @@ func (b InlineKbButtonBuilder) SetIconCustomEmojiId(id string) InlineKbButtonBui b.iconCustomEmojiID = id return b } -func (b InlineKbButtonBuilder) SetStyle(style InlineKeyboardButtonStyle) InlineKbButtonBuilder { +func (b InlineKbButtonBuilder) SetStyle(style KeyboardButtonStyle) InlineKbButtonBuilder { b.style = style return b } diff --git a/types.go b/types.go index 1d43b49..53121ef 100644 --- a/types.go +++ b/types.go @@ -128,13 +128,13 @@ type InlineKeyboardMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` } -type InlineKeyboardButtonStyle string +type KeyboardButtonStyle string type InlineKeyboardButton struct { - Text string `json:"text"` - URL string `json:"url,omitempty"` - CallbackData string `json:"callback_data,omitempty"` - Style InlineKeyboardButtonStyle `json:"style,omitempty"` - IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` + Text string `json:"text"` + URL string `json:"url,omitempty"` + CallbackData string `json:"callback_data,omitempty"` + Style KeyboardButtonStyle `json:"style,omitempty"` + IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` } type ReplyKeyboardMarkup struct { -- 2.53.0 From c1bdc2fdf6c2712dc18068611aa77dd0458e42a5 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 14:32:48 +0300 Subject: [PATCH 05/16] v0.4.3 --- keyboard.go | 13 ++++++++++--- version.go | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/keyboard.go b/keyboard.go index 128c40e..85d1095 100644 --- a/keyboard.go +++ b/keyboard.go @@ -72,20 +72,27 @@ func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard { in.CurrentLine = in.CurrentLine.Push(button) return in } + func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard { return in.append(InlineKeyboardButton{Text: text, URL: url}) } +func (in *InlineKeyboard) AddUrlButtonStyle(text string, style KeyboardButtonStyle, url string) *InlineKeyboard { + return in.append(InlineKeyboardButton{Text: text, Style: style, URL: url}) +} func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any) *InlineKeyboard { return in.append(InlineKeyboardButton{ Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson(), }) } +func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard { + return in.append(InlineKeyboardButton{ + Text: text, Style: style, + CallbackData: NewCallbackData(cmd, args...).ToJson(), + }) +} func (in *InlineKeyboard) AddButton(b InlineKbButtonBuilder) *InlineKeyboard { return in.append(b.build()) } -func (in *InlineKeyboard) AddCustomButton(button InlineKeyboardButton) *InlineKeyboard { - return in.append(button) -} func (in *InlineKeyboard) AddLine() *InlineKeyboard { if in.CurrentLine.Len() == 0 { diff --git a/version.go b/version.go index 95681a0..e23bd45 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.4.2" + VersionString = "0.4.3" VersionMajor = 0 VersionMinor = 4 - VersionPatch = 2 + VersionPatch = 3 ) -- 2.53.0 From a04375efbd0a1c7baad274336536752b2fc1c442 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 14:56:13 +0300 Subject: [PATCH 06/16] v0.4.4 --- types.go | 40 ++++++++++++++++++++++++++++++++-------- version.go | 4 ++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/types.go b/types.go index 53121ef..bcfd216 100644 --- a/types.go +++ b/types.go @@ -50,17 +50,41 @@ type MessageReplyMarkup struct { } type Message struct { - MessageID int `json:"message_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - From *User `json:"from,omitempty"` - Chat *Chat `json:"chat,omitempty"` - Text string `json:"text"` + MessageID int `json:"message_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + BusinessConnectionId string `json:"business_connection_id,omitempty"` + From *User `json:"from,omitempty"` - Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"` - Caption string `json:"caption,omitempty"` - ReplyToMessage *Message `json:"reply_to_message"` + SenderChat *Chat `json:"sender_chat,omitempty"` + SenderBoostCount int `json:"sender_boost_count,omitempty"` + SenderBusinessBot *User `json:"sender_business_bot,omitempty"` + Chat *Chat `json:"chat,omitempty"` + + IsTopicMessage bool `json:"is_topic_message,omitempty"` + IsAutomaticForward bool `json:"is_automatic_forward,omitempty"` + IsFromOffline bool `json:"is_from_offline,omitempty"` + IsPaidPost bool `json:"is_paid_post,omitempty"` + MediaGroupId string `json:"media_group_id,omitempty"` + AuthorSignature string `json:"author_signature,omitempty"` + PaidStarCount int `json:"paid_star_count,omitempty"` + ReplyToMessage *Message `json:"reply_to_message,omitempty"` + + Text string `json:"text"` + + Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"` + Caption string `json:"caption,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + Date int `json:"date"` + EditDate int `json:"edit_date"` ReplyMarkup *MessageReplyMarkup `json:"reply_markup,omitempty"` + + Entities []MessageEntity `json:"entities,omitempty"` + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + SuggestedPostInfo *SuggestedPostInfo `json:"suggested_post_info,omitempty"` + + EffectID string `json:"effect_id,omitempty"` } type InaccessableMessage struct { diff --git a/version.go b/version.go index e23bd45..37bdf59 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.4.3" + VersionString = "0.4.4" VersionMajor = 0 VersionMinor = 4 - VersionPatch = 3 + VersionPatch = 4 ) -- 2.53.0 From ef78c5d9b43e753d17ba58f9a63e1cc991d399e7 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 15:01:33 +0300 Subject: [PATCH 07/16] v0.4.4-1 --- types.go | 27 ++++++++++++++++++++++++++- version.go | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/types.go b/types.go index bcfd216..781b260 100644 --- a/types.go +++ b/types.go @@ -96,8 +96,33 @@ type InaccessableMessage struct { type MaybeInaccessibleMessage struct { } +type MessageEntityType string + +const ( + MessageEntityMention MessageEntityType = "mention" + MessageEntityHashtag MessageEntityType = "hashtag" + MessageEntityCashtag MessageEntityType = "cashtag" + MessageEntityBotCommand MessageEntityType = "bot_command" + MessageEntityUrl MessageEntityType = "url" + MessageEntityEmail MessageEntityType = "email" + MessageEntityPhoneNumber MessageEntityType = "phone_number" + MessageEntityBold MessageEntityType = "bold" + MessageEntityItalic MessageEntityType = "italic" + MessageEntityUnderline MessageEntityType = "underline" + MessageEntityStrike MessageEntityType = "strikethrough" + MessageEntitySpoiler MessageEntityType = "spoiler" + MessageEntityBlockquote MessageEntityType = "blockquote" + MessageEntityExpandableBlockquote MessageEntityType = "expandable_blockquote" + MessageEntityCode MessageEntityType = "code" + MessageEntityPre MessageEntityType = "pre" + MessageEntityTextLink MessageEntityType = "text_link" + MessageEntityTextMention MessageEntityType = "text_mention" + MessageEntityCustomEmoji MessageEntityType = "custom_emoji" +) + type MessageEntity struct { - Type string `json:"type"` + Type MessageEntityType `json:"type"` + Offset int `json:"offset"` Length int `json:"length"` URL string `json:"url,omitempty"` diff --git a/version.go b/version.go index 37bdf59..2b17a5f 100644 --- a/version.go +++ b/version.go @@ -1,7 +1,7 @@ package laniakea const ( - VersionString = "0.4.4" + VersionString = "0.4.4-1" VersionMajor = 0 VersionMinor = 4 VersionPatch = 4 -- 2.53.0 From 7ac293dd3889f375791fb2ba1497542766bf11ec Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Tue, 10 Feb 2026 17:06:15 +0300 Subject: [PATCH 08/16] stickers --- stickers.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 stickers.go diff --git a/stickers.go b/stickers.go new file mode 100644 index 0000000..a7f33fe --- /dev/null +++ b/stickers.go @@ -0,0 +1,93 @@ +package laniakea + +type MaskPositionPoint string + +const ( + MaskPositionForehead MaskPositionPoint = "forehead" + MaskPositionEyes MaskPositionPoint = "eyes" + MaskPositionMouth MaskPositionPoint = "mouth" + MaskPositionChin MaskPositionPoint = "chin" +) + +type MaskPosition struct { + Point MaskPositionPoint `json:"point"` + XShift float32 `json:"x_shift"` + YShift float32 `json:"y_shift"` + Scale float32 `json:"scale"` +} + +type StickerType string + +const ( + StickerTypeRegular StickerType = "regular" + StickerTypeMask StickerType = "mask" + StickerTypeCustomEmoji StickerType = "custom_emoji" +) + +type Sticker struct { + FileId string `json:"file_id"` + FileUniqueId string `json:"file_unique_id"` + Type StickerType `json:"type"` + Width int `json:"width"` + Height int `json:"height"` + IsAnimated bool `json:"is_animated"` + IsVideo bool `json:"is_video"` + + Thumbnail *PhotoSize `json:"thumbnail,omitempty"` + Emoji string `json:"emoji,omitempty"` + SetName string `json:"set_name,omitempty"` + MaskPosition *MaskPosition `json:"mask_position,omitempty"` + CustomEmojiID string `json:"custom_emoji_id,omitempty"` + NeedRepainting bool `json:"need_repainting,omitempty"` + FileSize int `json:"file_size,omitempty"` +} +type StickerSet struct { + Name string `json:"name"` + Title string `json:"title"` + StickerType StickerType `json:"sticker_type"` + Stickers []Sticker `json:"stickers"` + Thumbnail *PhotoSize `json:"thumbnail,omitempty"` +} +type InputStickerFormat string + +const ( + InputStickerFormatStatic InputStickerFormat = "static" + InputStickerFormatAnimated InputStickerFormat = "animated" + InputStickerFormatVideo InputStickerFormat = "video" +) + +type InputSticker struct { + Sticker string `json:"sticker"` + Format InputStickerFormat `json:"format"` + EmojiList []string `json:"emoji_list"` + MaskPosition *MaskPosition `json:"mask_position,omitempty"` + Keywords []string `json:"keywords,omitempty"` +} + +type SendStickerP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Sticker string `json:"sticker"` + Emoji string `json:"emoji,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` +} + +func (api *Api) SendSticker(p SendStickerP) (*Message, error) { + req := NewRequest[Message]("sendSticker", p) + return req.Do(api) +} + +type GetStickerSetP struct { + Name string `json:"name"` +} + +func (api *Api) GetStickerSet(p GetStickerSetP) (*StickerSet, error) { + req := NewRequest[StickerSet]("getStickerSet", p) + return req.Do(api) +} -- 2.53.0 From f2d85b848ff513b5b19e297032dc0b39c62a788e Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 11 Feb 2026 17:27:05 +0300 Subject: [PATCH 09/16] WIP v0.5.0 --- api.go | 91 ------ bot.go | 40 ++- handler.go | 6 +- keyboard.go | 43 +-- methods.go | 352 ++---------------------- msg_context.go | 61 ++-- tgapi/api.go | 105 +++++++ tgapi/attachments_methods.go | 262 ++++++++++++++++++ tgapi/attachments_types.go | 109 ++++++++ tgapi/bot_methods.go | 186 +++++++++++++ tgapi/bot_types.go | 99 +++++++ tgapi/business_methods.go | 149 ++++++++++ tgapi/business_types.go | 44 +++ tgapi/chat_methods.go | 337 +++++++++++++++++++++++ tgapi/chat_types.go | 242 ++++++++++++++++ tgapi/forum_methods.go | 86 ++++++ tgapi/forum_types.go | 15 + tgapi/messages_methods.go | 367 +++++++++++++++++++++++++ types.go => tgapi/messages_types.go | 174 +++++------- tgapi/methods.go | 41 +++ tgapi/stickers_methods.go | 166 +++++++++++ stickers.go => tgapi/stickers_types.go | 40 +-- tgapi/types.go | 113 ++++++++ uploader.go => tgapi/uploader.go | 27 +- tgapi/users_methods.go | 34 +++ tgapi/users_types.go | 40 +++ tgapi/utils.go | 15 + utils.go | 86 +----- multipart.go => utils/multipart.go | 2 +- utils/utils.go | 100 +++++++ utils/version.go | 8 + version.go | 8 - 32 files changed, 2721 insertions(+), 727 deletions(-) delete mode 100644 api.go create mode 100644 tgapi/api.go create mode 100644 tgapi/attachments_methods.go create mode 100644 tgapi/attachments_types.go create mode 100644 tgapi/bot_methods.go create mode 100644 tgapi/bot_types.go create mode 100644 tgapi/business_methods.go create mode 100644 tgapi/business_types.go create mode 100644 tgapi/chat_methods.go create mode 100644 tgapi/chat_types.go create mode 100644 tgapi/forum_methods.go create mode 100644 tgapi/forum_types.go create mode 100644 tgapi/messages_methods.go rename types.go => tgapi/messages_types.go (58%) create mode 100644 tgapi/methods.go create mode 100644 tgapi/stickers_methods.go rename stickers.go => tgapi/stickers_types.go (58%) create mode 100644 tgapi/types.go rename uploader.go => tgapi/uploader.go (70%) create mode 100644 tgapi/users_methods.go create mode 100644 tgapi/users_types.go create mode 100644 tgapi/utils.go rename multipart.go => utils/multipart.go (99%) create mode 100644 utils/utils.go create mode 100644 utils/version.go delete mode 100644 version.go diff --git a/api.go b/api.go deleted file mode 100644 index 6fa7458..0000000 --- a/api.go +++ /dev/null @@ -1,91 +0,0 @@ -package laniakea - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - - "git.nix13.pw/scuroneko/slog" -) - -type Api struct { - token string - logger *slog.Logger -} - -func NewAPI(token string) *Api { - l := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("API") - l.AddWriter(l.CreateJsonStdoutWriter()) - return &Api{token, l} -} -func (api *Api) CloseApi() error { - return api.logger.Close() -} - -type ApiResponse[R any] struct { - Ok bool `json:"ok"` - Description string `json:"description,omitempty"` - Result R `json:"result,omitempty"` - ErrorCode int `json:"error_code,omitempty"` -} - -type TelegramRequest[R, P any] struct { - method string - params P -} - -func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] { - return TelegramRequest[R, P]{method: method, params: params} -} -func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) { - buf := bytes.NewBuffer(nil) - err := json.NewEncoder(buf).Encode(r.params) - if err != nil { - return nil, err - } - - u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method) - if api.logger != nil { - api.logger.Debugln(strings.ReplaceAll(fmt.Sprintf( - "POST %s %s", u, buf.String(), - ), api.token, "")) - } - - res, err := http.Post(u, "application/json", buf) - if err != nil { - return nil, err - } - defer res.Body.Close() - data, err := io.ReadAll(res.Body) - if err != nil { - return nil, err - } - - if api.logger != nil { - api.logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) - } - - response := new(ApiResponse[R]) - err = json.Unmarshal(data, &response) - if err != nil { - return nil, err - } - - if !response.Ok { - return nil, fmt.Errorf("[%d] %s", response.ErrorCode, response.Description) - } - return &response.Result, nil -} - -func (b *Bot) GetFileByLink(link string) ([]byte, error) { - u := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", b.token, link) - res, err := http.Get(u) - if err != nil { - return nil, err - } - defer res.Body.Close() - return io.ReadAll(res.Body) -} diff --git a/bot.go b/bot.go index f17db42..e92db57 100644 --- a/bot.go +++ b/bot.go @@ -9,27 +9,20 @@ import ( "time" "git.nix13.pw/scuroneko/extypes" + "git.nix13.pw/scuroneko/laniakea/tgapi" "git.nix13.pw/scuroneko/slog" "github.com/redis/go-redis/v9" "github.com/vinovest/sqlx" "go.mongodb.org/mongo-driver/v2/mongo" ) -type ParseMode string - -const ( - ParseMDV2 ParseMode = "MarkdownV2" - ParseHTML ParseMode = "HTML" - ParseMD ParseMode = "Markdown" -) - type Bot struct { token string debug bool errorTemplate string logger *slog.Logger - requestLogger *slog.Logger + RequestLogger *slog.Logger plugins []Plugin middlewares []Middleware @@ -37,15 +30,20 @@ type Bot struct { runners []Runner dbContext *DatabaseContext - api *Api + api *tgapi.Api dbWriterRequested extypes.Slice[*slog.Logger] updateOffset int updateTypes []string - updateQueue *extypes.Queue[*Update] + updateQueue *extypes.Queue[*tgapi.Update] } +func (b *Bot) GetUpdateOffset() int { return b.updateOffset } +func (b *Bot) SetUpdateOffset(offset int) { b.updateOffset = offset } +func (b *Bot) GetUpdateTypes() []string { return b.updateTypes } +func (b *Bot) GetQueue() *extypes.Queue[*tgapi.Update] { return b.updateQueue } + type BotSettings struct { Token string Debug bool @@ -77,15 +75,15 @@ func LoadPrefixesFromEnv() []string { return strings.Split(prefixesS, ";") } func NewBot(settings *BotSettings) *Bot { - updateQueue := extypes.CreateQueue[*Update](256) - api := NewAPI(settings.Token) + updateQueue := extypes.CreateQueue[*tgapi.Update](256) + api := tgapi.NewAPI(settings.Token) bot := &Bot{ updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s", prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0), updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0), token: settings.Token, } - bot.dbWriterRequested = bot.dbWriterRequested.Push(api.logger) + bot.dbWriterRequested = bot.dbWriterRequested.Push(api.Logger) if len(settings.ErrorTemplate) > 0 { bot.errorTemplate = settings.ErrorTemplate @@ -111,15 +109,15 @@ func NewBot(settings *BotSettings) *Bot { } if settings.UseRequestLogger { - bot.requestLogger = slog.CreateLogger().Level(level).Prefix("REQUESTS") - bot.requestLogger.AddWriter(bot.requestLogger.CreateJsonStdoutWriter()) + bot.RequestLogger = slog.CreateLogger().Level(level).Prefix("REQUESTS") + bot.RequestLogger.AddWriter(bot.RequestLogger.CreateJsonStdoutWriter()) if settings.WriteToFile { path := fmt.Sprintf("%s/requests.log", strings.TrimRight(settings.LoggerBasePath, "/")) - fileWriter, err := bot.requestLogger.CreateTextFileWriter(path) + fileWriter, err := bot.RequestLogger.CreateTextFileWriter(path) if err != nil { bot.logger.Fatal(err) } - bot.requestLogger.AddWriter(fileWriter) + bot.RequestLogger.AddWriter(fileWriter) } } @@ -137,7 +135,7 @@ func (b *Bot) Close() { if err != nil { log.Println(err) } - err = b.requestLogger.Close() + err = b.RequestLogger.Close() if err != nil { log.Println(err) } @@ -152,8 +150,8 @@ type DatabaseContext struct { func (b *Bot) AddDatabaseLogger(writer func(db *DatabaseContext) slog.LoggerWriter) *Bot { w := writer(b.dbContext) b.logger.AddWriter(w) - if b.requestLogger != nil { - b.requestLogger.AddWriter(w) + if b.RequestLogger != nil { + b.RequestLogger.AddWriter(w) } for _, l := range b.dbWriterRequested { l.AddWriter(w) diff --git a/handler.go b/handler.go index 487843d..464161c 100644 --- a/handler.go +++ b/handler.go @@ -3,9 +3,11 @@ package laniakea import ( "encoding/json" "strings" + + "git.nix13.pw/scuroneko/laniakea/tgapi" ) -func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { +func (b *Bot) handleMessage(update *tgapi.Update, ctx *MsgContext) { if update.Message == nil { return } @@ -60,7 +62,7 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { } } -func (b *Bot) handleCallback(update *Update, ctx *MsgContext) { +func (b *Bot) handleCallback(update *tgapi.Update, ctx *MsgContext) { data := new(CallbackData) err := json.Unmarshal([]byte(update.CallbackQuery.Data), data) if err != nil { diff --git a/keyboard.go b/keyboard.go index 85d1095..01b400e 100644 --- a/keyboard.go +++ b/keyboard.go @@ -5,18 +5,19 @@ import ( "fmt" "git.nix13.pw/scuroneko/extypes" + "git.nix13.pw/scuroneko/laniakea/tgapi" ) const ( - ButtonStyleDanger KeyboardButtonStyle = "danger" - ButtonStyleSuccess KeyboardButtonStyle = "success" - ButtonStylePrimary KeyboardButtonStyle = "primary" + ButtonStyleDanger tgapi.KeyboardButtonStyle = "danger" + ButtonStyleSuccess tgapi.KeyboardButtonStyle = "success" + ButtonStylePrimary tgapi.KeyboardButtonStyle = "primary" ) type InlineKbButtonBuilder struct { text string iconCustomEmojiID string - style KeyboardButtonStyle + style tgapi.KeyboardButtonStyle url string callbackData string } @@ -28,7 +29,7 @@ func (b InlineKbButtonBuilder) SetIconCustomEmojiId(id string) InlineKbButtonBui b.iconCustomEmojiID = id return b } -func (b InlineKbButtonBuilder) SetStyle(style KeyboardButtonStyle) InlineKbButtonBuilder { +func (b InlineKbButtonBuilder) SetStyle(style tgapi.KeyboardButtonStyle) InlineKbButtonBuilder { b.style = style return b } @@ -41,8 +42,8 @@ func (b InlineKbButtonBuilder) SetCallbackData(cmd string, args ...any) InlineKb return b } -func (b InlineKbButtonBuilder) build() InlineKeyboardButton { - return InlineKeyboardButton{ +func (b InlineKbButtonBuilder) build() tgapi.InlineKeyboardButton { + return tgapi.InlineKeyboardButton{ Text: b.text, URL: b.url, Style: b.style, @@ -52,20 +53,20 @@ func (b InlineKbButtonBuilder) build() InlineKeyboardButton { } type InlineKeyboard struct { - CurrentLine extypes.Slice[InlineKeyboardButton] - Lines [][]InlineKeyboardButton + CurrentLine extypes.Slice[tgapi.InlineKeyboardButton] + Lines [][]tgapi.InlineKeyboardButton maxRow int } func NewInlineKeyboard(maxRow int) *InlineKeyboard { return &InlineKeyboard{ - CurrentLine: make(extypes.Slice[InlineKeyboardButton], 0), - Lines: make([][]InlineKeyboardButton, 0), + CurrentLine: make(extypes.Slice[tgapi.InlineKeyboardButton], 0), + Lines: make([][]tgapi.InlineKeyboardButton, 0), maxRow: maxRow, } } -func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard { +func (in *InlineKeyboard) append(button tgapi.InlineKeyboardButton) *InlineKeyboard { if in.CurrentLine.Len() == in.maxRow { in.AddLine() } @@ -74,18 +75,18 @@ func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard { } func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard { - return in.append(InlineKeyboardButton{Text: text, URL: url}) + return in.append(tgapi.InlineKeyboardButton{Text: text, URL: url}) } -func (in *InlineKeyboard) AddUrlButtonStyle(text string, style KeyboardButtonStyle, url string) *InlineKeyboard { - return in.append(InlineKeyboardButton{Text: text, Style: style, URL: url}) +func (in *InlineKeyboard) AddUrlButtonStyle(text string, style tgapi.KeyboardButtonStyle, url string) *InlineKeyboard { + return in.append(tgapi.InlineKeyboardButton{Text: text, Style: style, URL: url}) } func (in *InlineKeyboard) AddCallbackButton(text string, cmd string, args ...any) *InlineKeyboard { - return in.append(InlineKeyboardButton{ + return in.append(tgapi.InlineKeyboardButton{ Text: text, CallbackData: NewCallbackData(cmd, args...).ToJson(), }) } -func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard { - return in.append(InlineKeyboardButton{ +func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style tgapi.KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard { + return in.append(tgapi.InlineKeyboardButton{ Text: text, Style: style, CallbackData: NewCallbackData(cmd, args...).ToJson(), }) @@ -99,14 +100,14 @@ func (in *InlineKeyboard) AddLine() *InlineKeyboard { return in } in.Lines = append(in.Lines, in.CurrentLine) - in.CurrentLine = make(extypes.Slice[InlineKeyboardButton], 0) + in.CurrentLine = make(extypes.Slice[tgapi.InlineKeyboardButton], 0) return in } -func (in *InlineKeyboard) Get() *InlineKeyboardMarkup { +func (in *InlineKeyboard) Get() *tgapi.ReplyMarkup { if in.CurrentLine.Len() > 0 { in.Lines = append(in.Lines, in.CurrentLine) } - return &InlineKeyboardMarkup{InlineKeyboard: in.Lines} + return &tgapi.ReplyMarkup{InlineKeyboard: in.Lines} } type CallbackData struct { diff --git a/methods.go b/methods.go index 48a35ef..f2b240b 100644 --- a/methods.go +++ b/methods.go @@ -2,359 +2,51 @@ package laniakea import ( "encoding/json" + "fmt" + "io" + "net/http" + + "git.nix13.pw/scuroneko/laniakea/tgapi" ) -type EmptyParams struct{} - -var NoParams = EmptyParams{} - -type UpdateParams struct { - Offset int `json:"offset"` - Timeout int `json:"timeout"` - AllowedUpdates []string `json:"allowed_updates"` -} - -func (b *Bot) Updates() ([]*Update, error) { - params := UpdateParams{ - Offset: b.updateOffset, +func (b *Bot) Updates() ([]*tgapi.Update, error) { + offset := b.GetUpdateOffset() + params := tgapi.UpdateParams{ + Offset: offset, Timeout: 30, - AllowedUpdates: b.updateTypes, + AllowedUpdates: b.GetUpdateTypes(), } - req := NewRequest[[]*Update]("getUpdates", params) + req := tgapi.NewRequest[[]*tgapi.Update]("getUpdates", params) res, err := req.Do(b.api) if err != nil { return nil, err } for _, u := range *res { - b.updateOffset = u.UpdateID + 1 - err = b.updateQueue.Enqueue(u) + b.SetUpdateOffset(u.UpdateID + 1) + err = b.GetQueue().Enqueue(u) if err != nil { return nil, err } - if b.requestLogger != nil { + if b.RequestLogger != nil { j, err := json.Marshal(u) if err != nil { - b.logger.Error(err) + b.Logger().Error(err) } - b.requestLogger.Debugf("UPDATE %s\n", j) + b.RequestLogger.Debugf("UPDATE %s\n", j) } } return *res, err } -func (api *Api) GetMe() (*User, error) { - req := NewRequest[User, EmptyParams]("getMe", NoParams) - return req.Do(api) -} -func (api *Api) LogOut() (bool, error) { - req := NewRequest[bool, EmptyParams]("logOut", NoParams) - res, err := req.Do(api) +func (b *Bot) GetFileByLink(link string) ([]byte, error) { + u := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", b.token, link) + res, err := http.Get(u) if err != nil { - return false, err + return nil, err } - return *res, nil -} -func (api *Api) Close() (bool, error) { - req := NewRequest[bool, EmptyParams]("close", NoParams) - res, err := req.Do(api) - if err != nil { - return false, err - } - return *res, nil -} - -type SendMessageP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` - - Text string `json:"text"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Entities []*MessageEntity `json:"entities,omitempty"` - LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - - SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` - ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -func (api *Api) SendMessage(params *SendMessageP) (*Message, error) { - req := NewRequest[Message, SendMessageP]("sendMessage", *params) - return req.Do(api) -} - -type ForwardMessageP struct { - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` - - MessageID int `json:"message_id,omitempty"` - FromChatID int `json:"from_chat_id,omitempty"` - VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - - MessageEffectID string `json:"message_effect_id,omitempty"` - SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` -} - -func (api *Api) ForwardMessage(params ForwardMessageP) (*Message, error) { - req := NewRequest[Message]("forwardMessage", params) - return req.Do(api) -} - -type ForwardMessagesP struct { - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` - - FromChatID int `json:"from_chat_id,omitempty"` - MessageIDs []int `json:"message_ids,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` -} - -func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) { - req := NewRequest[[]int]("forwardMessages", params) - res, err := req.Do(api) - if err != nil { - return []int{}, err - } - return *res, nil -} - -type CopyMessageP struct { - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` - - FromChatID int `json:"from_chat_id"` - MessageID int `json:"message_id"` - VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - - SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` - ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -func (api *Api) CopyMessage(params CopyMessageP) (int, error) { - req := NewRequest[int]("copyMessage", params) - res, err := req.Do(api) - if err != nil { - return 0, err - } - return *res, nil -} - -type CopyMessagesP struct { - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` - - FromChatID int `json:"from_chat_id,omitempty"` - MessageIDs []int `json:"message_ids,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - RemoveCaption bool `json:"remove_caption,omitempty"` -} - -func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) { - req := NewRequest[[]int]("copyMessages", params) - res, err := req.Do(api) - if err != nil { - return []int{}, err - } - return *res, nil -} - -type SendPhotoBaseP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} -type SendPhotoP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - - Photo string `json:"photo"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - - SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` - ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -func (api *Api) SendPhoto(params *SendPhotoP) (*Message, error) { - req := NewRequest[Message]("sendPhoto", params) - return req.Do(api) -} - -type EditMessageTextP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Text string `json:"text"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -func (api *Api) EditMessageText(params *EditMessageTextP) (*Message, error) { - req := NewRequest[Message]("editMessageText", params) - return req.Do(api) -} - -type EditMessageCaptionP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Caption string `json:"caption"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) { - req := NewRequest[Message]("editMessageCaption", params) - return req.Do(api) -} - -type DeleteMessageP struct { - ChatID int `json:"chat_id"` - MessageID int `json:"message_id"` -} - -func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) { - req := NewRequest[bool]("deleteMessage", params) - ok, err := req.Do(api) - if err != nil { - return false, err - } - return *ok, err -} - -type AnswerCallbackQueryP struct { - CallbackQueryID string `json:"callback_query_id"` - Text string `json:"text,omitempty"` - ShowAlert bool `json:"show_alert,omitempty"` - URL string `json:"url,omitempty"` - CacheTime int `json:"cache_time,omitempty"` -} - -func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { - req := NewRequest[bool]("answerCallbackQuery", params) - ok, err := req.Do(api) - if err != nil { - return false, err - } - return *ok, err -} - -type GetFileP struct { - FileId string `json:"file_id"` -} - -func (api *Api) GetFile(params *GetFileP) (*File, error) { - req := NewRequest[File]("getFile", params) - return req.Do(api) -} - -type SendChatActionP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - Action ChatActions `json:"action"` -} - -func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { - req := NewRequest[bool]("sendChatAction", params) - res, err := req.Do(api) - if err != nil { - return false, err - } - return *res, err -} - -type SetMessageReactionP struct { - ChatId int `json:"chat_id"` - MessageId int `json:"message_id"` - IsBig bool `json:"is_big,omitempty"` -} -type SetMessageReactionEmojiP struct { - SetMessageReactionP - Reaction []ReactionTypeEmoji `json:"reaction"` -} - -func (api *Api) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) { - req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(api) - if err != nil { - return false, err - } - return *res, err -} - -type SetMessageReactionCustomEmojiP struct { - SetMessageReactionP - Reaction []ReactionTypeCustomEmoji `json:"reaction"` -} - -func (api *Api) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) { - req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(api) - if err != nil { - return false, err - } - return *res, err -} - -type SetMessageReactionPaidP struct { - SetMessageReactionP -} - -func (api *Api) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) { - req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(api) - if err != nil { - return false, err - } - return *res, err + defer res.Body.Close() + return io.ReadAll(res.Body) } diff --git a/msg_context.go b/msg_context.go index fa9f2c0..922ba4f 100644 --- a/msg_context.go +++ b/msg_context.go @@ -1,14 +1,19 @@ package laniakea -import "fmt" +import ( + "fmt" + + "git.nix13.pw/scuroneko/laniakea/tgapi" + "git.nix13.pw/scuroneko/laniakea/utils" +) type MsgContext struct { Bot *Bot - Api *Api + Api *tgapi.Api - Msg *Message - Update *Update - From *User + Msg *tgapi.Message + Update *tgapi.Update + From *tgapi.User CallbackMsgId int CallbackQueryId string FromID int @@ -26,18 +31,18 @@ type AnswerMessage struct { } func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard) *AnswerMessage { - params := &EditMessageTextP{ + params := &tgapi.EditMessageTextP{ MessageID: messageId, ChatID: ctx.Msg.Chat.ID, Text: text, - ParseMode: ParseMD, + ParseMode: tgapi.ParseMD, } if keyboard != nil { params.ReplyMarkup = keyboard.Get() } msg, err := ctx.Api.EditMessageText(params) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) return nil } return &AnswerMessage{ @@ -49,7 +54,7 @@ func (m *AnswerMessage) Edit(text string) *AnswerMessage { } func (ctx *MsgContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage { if ctx.CallbackMsgId == 0 { - ctx.Api.logger.Errorln("Can't edit non-callback update message") + ctx.Api.Logger.Errorln("Can't edit non-callback update message") return nil } @@ -60,18 +65,18 @@ func (ctx *MsgContext) EditCallbackf(format string, keyboard *InlineKeyboard, ar } func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeyboard) *AnswerMessage { - params := &EditMessageCaptionP{ + params := &tgapi.EditMessageCaptionP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, Caption: text, - ParseMode: ParseMD, + ParseMode: tgapi.ParseMD, } if kb != nil { params.ReplyMarkup = kb.Get() } msg, err := ctx.Api.EditMessageCaption(params) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) } return &AnswerMessage{ MessageID: msg.MessageID, ctx: ctx, Text: text, IsMedia: true, @@ -79,7 +84,7 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo } func (m *AnswerMessage) EditCaption(text string) *AnswerMessage { if m.MessageID == 0 { - m.ctx.Api.logger.Errorln("Can't edit caption message, message id is zero") + m.ctx.Api.Logger.Errorln("Can't edit caption message, message id is zero") return m } return m.ctx.editPhotoText(m.MessageID, text, nil) @@ -89,10 +94,10 @@ func (m *AnswerMessage) EditCaptionKeyboard(text string, kb *InlineKeyboard) *An } func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMessage { - params := &SendMessageP{ + params := &tgapi.SendMessageP{ ChatID: ctx.Msg.Chat.ID, Text: text, - ParseMode: ParseMD, + ParseMode: tgapi.ParseMD, } if keyboard != nil { params.ReplyMarkup = keyboard.Get() @@ -100,7 +105,7 @@ func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMess msg, err := ctx.Api.SendMessage(params) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) return nil } return &AnswerMessage{ @@ -118,10 +123,10 @@ func (ctx *MsgContext) Keyboard(text string, kb *InlineKeyboard) *AnswerMessage } func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *AnswerMessage { - params := &SendPhotoP{ + params := &tgapi.SendPhotoP{ ChatID: ctx.Msg.Chat.ID, Caption: text, - ParseMode: ParseMD, + ParseMode: tgapi.ParseMD, Photo: photoId, } if kb != nil { @@ -129,7 +134,7 @@ func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *An } msg, err := ctx.Api.SendPhoto(params) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) return &AnswerMessage{ ctx: ctx, Text: text, IsMedia: true, } @@ -146,12 +151,12 @@ func (ctx *MsgContext) AnswerPhotoKeyboard(photoId, text string, kb *InlineKeybo } func (ctx *MsgContext) delete(messageId int) { - _, err := ctx.Api.DeleteMessage(&DeleteMessageP{ + _, err := ctx.Api.DeleteMessage(&tgapi.DeleteMessageP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, }) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) } } func (m *AnswerMessage) Delete() { @@ -165,12 +170,12 @@ func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) { if len(ctx.CallbackQueryId) == 0 { return } - _, err := ctx.Api.AnswerCallbackQuery(&AnswerCallbackQueryP{ + _, err := ctx.Api.AnswerCallbackQuery(&tgapi.AnswerCallbackQueryP{ CallbackQueryID: ctx.CallbackQueryId, Text: text, ShowAlert: showAlert, URL: url, }) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) } } func (ctx *MsgContext) AnswerCbQuery() { @@ -186,24 +191,24 @@ func (ctx *MsgContext) AnswerCbQueryUrl(u string) { ctx.answerCallbackQuery(u, "", false) } -func (ctx *MsgContext) SendAction(action ChatActions) { - _, err := ctx.Api.SendChatAction(SendChatActionP{ +func (ctx *MsgContext) SendAction(action tgapi.ChatActionType) { + _, err := ctx.Api.SendChatAction(tgapi.SendChatActionP{ ChatID: ctx.Msg.Chat.ID, Action: action, }) if err != nil { - ctx.Api.logger.Errorln(err) + ctx.Api.Logger.Errorln(err) } } func (ctx *MsgContext) error(err error) { - text := fmt.Sprintf(ctx.Bot.errorTemplate, EscapeMarkdown(err.Error())) + text := fmt.Sprintf(ctx.Bot.errorTemplate, utils.EscapeMarkdown(err.Error())) if ctx.CallbackQueryId != "" { ctx.answerCallbackQuery("", text, false) } else { ctx.answer(text, nil) } - ctx.Bot.logger.Errorln(err) + ctx.Bot.Logger().Errorln(err) } func (ctx *MsgContext) Error(err error) { ctx.error(err) diff --git a/tgapi/api.go b/tgapi/api.go new file mode 100644 index 0000000..bb3ba9f --- /dev/null +++ b/tgapi/api.go @@ -0,0 +1,105 @@ +package tgapi + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "git.nix13.pw/scuroneko/laniakea/utils" + "git.nix13.pw/scuroneko/slog" +) + +type Api struct { + token string + client *http.Client + Logger *slog.Logger +} + +func NewAPI(token string) *Api { + l := slog.CreateLogger().Level(utils.GetLoggerLevel()).Prefix("API") + l.AddWriter(l.CreateJsonStdoutWriter()) + client := &http.Client{Timeout: time.Second * 10} + return &Api{token, client, l} +} +func (api *Api) CloseApi() error { + return api.Logger.Close() +} + +type ApiResponse[R any] struct { + Ok bool `json:"ok"` + Description string `json:"description,omitempty"` + Result R `json:"result,omitempty"` + ErrorCode int `json:"error_code,omitempty"` +} + +type TelegramRequest[R, P any] struct { + method string + params P +} + +func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] { + return TelegramRequest[R, P]{method: method, params: params} +} +func (r TelegramRequest[R, P]) DoWithContext(ctx context.Context, api *Api) (R, error) { + var zero R + data, err := json.Marshal(r.params) + if err != nil { + return zero, err + } + buf := bytes.NewBuffer(data) + + u := fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method) + if api.Logger != nil { + api.Logger.Debugln(strings.ReplaceAll(fmt.Sprintf( + "POST %s %s", u, buf.String(), + ), api.token, "")) + } + + req, err := http.NewRequestWithContext(ctx, "POST", u, buf) + if err != nil { + return zero, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString)) + + res, err := api.client.Do(req) + if err != nil { + return zero, err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return zero, fmt.Errorf("unexpected status code: %d", res.StatusCode) + } + + reader := io.LimitReader(res.Body, 10<<20) + data, err = io.ReadAll(reader) + if err != nil { + return zero, err + } + + if api.Logger != nil { + api.Logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) + } + + var resp ApiResponse[R] + err = json.Unmarshal(data, &resp) + if err != nil { + return zero, err + } + + if !resp.Ok { + return zero, fmt.Errorf("[%d] %s", resp.ErrorCode, resp.Description) + } + return resp.Result, nil + +} +func (r TelegramRequest[R, P]) Do(api *Api) (R, error) { + ctx := context.Background() + return r.DoWithContext(ctx, api) +} diff --git a/tgapi/attachments_methods.go b/tgapi/attachments_methods.go new file mode 100644 index 0000000..4dc7c3d --- /dev/null +++ b/tgapi/attachments_methods.go @@ -0,0 +1,262 @@ +package tgapi + +type SendPhotoP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Photo string `json:"photo"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendPhoto(params SendPhotoP) (Message, error) { + req := NewRequest[Message]("sendPhoto", params) + return req.Do(api) +} + +type SendAudioP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Audio string `json:"audio"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendAudio(params SendAudioP) (Message, error) { + req := NewRequest[Message]("sendAudio", params) + return req.Do(api) +} + +type SendDocumentP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Document string `json:"document"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendDocument(params SendDocumentP) (Message, error) { + req := NewRequest[Message]("sendDocument", params) + return req.Do(api) +} + +type SendVideoP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Video string `json:"video"` + Duration int `json:"duration,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Cover string `json:"cover,omitempty"` + + StartTimestamp int `json:"start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + SupportsStreaming bool `json:"supports_streaming,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendVideo(params SendVideoP) (Message, error) { + req := NewRequest[Message]("sendVideo", params) + return req.Do(api) +} + +type SendAnimationP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Animation string `json:"animation"` + Duration int `json:"duration,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendAnimation(p SendAnimationP) (Message, error) { + req := NewRequest[Message]("sendAnimation", p) + return req.Do(api) +} + +type SendVoiceP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Voice string `json:"voice"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendVoice(params *SendVoiceP) (Message, error) { + req := NewRequest[Message]("sendVoice", params) + return req.Do(api) +} + +type SendVideoNoteP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + VideoNote string `json:"video_note"` + Duration int `json:"duration,omitempty"` + Length int `json:"length,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendVideoNote(params SendVideoNoteP) (Message, error) { + req := NewRequest[Message]("sendVideoNote", params) + return req.Do(api) +} + +type SendPaidMediaP[T InputPaidMedia] struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + StarCount int `json:"star_count,omitempty"` + + Media []T `json:"media"` + Payload string `json:"payload,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendPaidMediaPhoto(params SendPaidMediaP[InputPaidMediaPhoto]) (Message, error) { + req := NewRequest[Message]("sendPaidMedia", params) + return req.Do(api) +} +func (api *Api) SendPaidMediaVideo(params SendPaidMediaP[InputPaidMediaVideo]) (Message, error) { + req := NewRequest[Message]("sendPaidMedia", params) + return req.Do(api) +} + +type SendMediaGroupP[T InputMedia] struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Media []T `json:"media"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` +} + +func (api *Api) SendMediaGroupAudio(p SendMediaGroupP[InputMediaAudio]) (Message, error) { + req := NewRequest[Message]("sendMediaGroupAudio", p) + return req.Do(api) +} +func (api *Api) SendMediaGroupDocument(p SendMediaGroupP[InputMediaDocument]) (Message, error) { + req := NewRequest[Message]("sendMediaGroupDocument", p) + return req.Do(api) +} +func (api *Api) SendMediaGroupPhoto(p SendMediaGroupP[InputMediaPhoto]) (Message, error) { + req := NewRequest[Message]("sendMediaGroupPhoto", p) + return req.Do(api) +} +func (api *Api) SendMediaGroupVideo(p SendMediaGroupP[InputMediaVideo]) (Message, error) { + req := NewRequest[Message]("sendMediaGroupVideo", p) + return req.Do(api) +} diff --git a/tgapi/attachments_types.go b/tgapi/attachments_types.go new file mode 100644 index 0000000..2fa8072 --- /dev/null +++ b/tgapi/attachments_types.go @@ -0,0 +1,109 @@ +package tgapi + +type InputMedia interface { + InputMediaPhoto | InputMediaVideo | InputMediaAudio | InputMediaDocument +} + +type InputMediaType string + +const ( + InputMediaTypeAnimation InputMediaType = "animation" + InputMediaTypeDocument InputMediaType = "document" + InputMediaTypePhoto InputMediaType = "photo" + InputMediaTypeVideo InputMediaType = "video" + InputMediaTypeAudio InputMediaType = "audio" +) + +type InputMediaPhoto struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` +} +type InputMediaVideo struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Cover string `json:"cover"` + StartTimestamp int `json:"start_timestamp"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Duration int `json:"duration,omitempty"` + SupportsStreaming bool `json:"supports_streaming,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` +} +type InputMediaAnimation struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Duration int `json:"duration,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` +} +type InputMediaAudio struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` +} +type InputMediaDocument struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` +} + +type InputPaidMediaType string + +const ( + InputPaidMediaTypeVideo InputPaidMediaType = "video" + InputPaidMediaTypePhoto InputPaidMediaType = "photo" +) + +type InputPaidMedia interface { + InputPaidMediaVideo | InputPaidMediaPhoto +} +type InputPaidMediaPhoto struct { + Type InputPaidMediaType `json:"type"` + Media string `json:"media"` +} +type InputPaidMediaVideo struct { + Type InputPaidMediaType `json:"type"` + Media string `json:"media"` + + Cover string `json:"cover"` + StartTimestamp int64 `json:"start_timestamp"` + Width int `json:"width"` + Height int `json:"height"` + Duration int `json:"duration"` + SupportsStreaming bool `json:"supports_streaming"` +} + +type PhotoSize struct { + FileID string `json:"file_id"` + FileUniqueID string `json:"file_unique_id"` + Width int `json:"width"` + Height int `json:"height"` + FileSize int `json:"file_size,omitempty"` +} diff --git a/tgapi/bot_methods.go b/tgapi/bot_methods.go new file mode 100644 index 0000000..cdc887b --- /dev/null +++ b/tgapi/bot_methods.go @@ -0,0 +1,186 @@ +package tgapi + +type SetMyCommandsP struct { + Commands []BotCommand `json:"commands"` + Scope *BaseBotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) SetMyCommands(p SetMyCommandsP) (bool, error) { + req := NewRequest[bool]("setMyCommands", p) + return req.Do(api) +} + +type DeleteMyCommandsP struct { + Scope *BaseBotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) DeleteMyCommands(p DeleteMyCommandsP) (bool, error) { + req := NewRequest[bool]("deleteMyCommands", p) + return req.Do(api) +} + +type GetMyCommands struct { + Scope *BaseBotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) GetMyCommands(p GetMyCommands) ([]BotCommand, error) { + req := NewRequest[[]BotCommand]("getMyCommands", p) + return req.Do(api) +} + +type SetMyName struct { + Name string `json:"name"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) SetMyName(p SetMyName) (bool, error) { + req := NewRequest[bool]("setMyName", p) + return req.Do(api) +} + +type GetMyName struct { + Language string `json:"language_code,omitempty"` +} + +func (api *Api) GetMyName(p GetMyName) (BotName, error) { + req := NewRequest[BotName]("getMyName", p) + return req.Do(api) +} + +type SetMyDescription struct { + Description string `json:"description"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) SetMyDescription(p SetMyDescription) (bool, error) { + req := NewRequest[bool]("setMyDescription", p) + return req.Do(api) +} + +type GetMyDescription struct { + Language string `json:"language_code,omitempty"` +} + +func (api *Api) GetMyDescription(p GetMyDescription) (BotDescription, error) { + req := NewRequest[BotDescription]("getMyDescription", p) + return req.Do(api) +} + +type SetMyShortDescription struct { + ShortDescription string `json:"short_description,omitempty"` + Language string `json:"language_code,omitempty"` +} + +func (api *Api) SetMyShortDescription(p SetMyShortDescription) (bool, error) { + req := NewRequest[bool]("setMyShortDescription", p) + return req.Do(api) +} + +type GetMyShortDescription struct { + Language string `json:"language_code,omitempty"` +} + +func (api *Api) GetMyShortDescription(p GetMyShortDescription) (BotShortDescription, error) { + req := NewRequest[BotShortDescription]("getMyShortDescription", p) + return req.Do(api) +} + +type SetMyProfilePhotoP[T InputProfilePhoto] struct { + Photo T `json:"photo"` +} + +func (api *Api) SetMyProfilePhotoStatic(p SetMyProfilePhotoP[InputProfilePhotoStatic]) (bool, error) { + req := NewRequest[bool]("setMyProfilePhoto", p) + return req.Do(api) +} +func (api *Api) SetMyProfilePhotoAnimated(p SetMyProfilePhotoP[InputProfilePhotoAnimated]) (bool, error) { + req := NewRequest[bool]("setMyProfilePhoto", p) + return req.Do(api) +} +func (api *Api) RemoveMyProfilePhoto() (bool, error) { + req := NewRequest[bool]("removeMyProfilePhoto", NoParams) + return req.Do(api) +} + +type SetChatMenuButtonP[T MenuButton] struct { + ChatID int `json:"chat_id"` + MenuButton T `json:"menu_button"` +} + +func (api *Api) SetChatMenuButtonCommands(p SetChatMenuButtonP[MenuButtonCommands]) (bool, error) { + req := NewRequest[bool]("setChatMenuButton", p) + return req.Do(api) +} +func (api *Api) SetChatMenuButtonWebApp(p SetChatMenuButtonP[MenuButtonWebApp]) (bool, error) { + req := NewRequest[bool]("setChatMenuButton", p) + return req.Do(api) +} +func (api *Api) SetChatMenuButtonDefault(p SetChatMenuButtonP[MenuButtonDefault]) (bool, error) { + req := NewRequest[bool]("setChatMenuButton", p) + return req.Do(api) +} + +type GetChatMenuButtonP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) GetChatMenuButton(p GetChatMenuButtonP) (BaseMenuButton, error) { + req := NewRequest[BaseMenuButton]("getChatMenuButton", p) + return req.Do(api) +} + +type SetMyDefaultAdministratorRightsP struct { + Rights *ChatAdministratorRights `json:"rights"` + ForChannels bool `json:"for_channels"` +} + +func (api *Api) SetMyDefaultAdministratorRights(p SetMyDefaultAdministratorRightsP) (bool, error) { + req := NewRequest[bool]("setMyDefaultAdministratorRights", p) + return req.Do(api) +} + +type GetMyDefaultAdministratorRightsP struct { + ForChannels bool `json:"for_channels"` +} + +func (api *Api) GetMyDefaultAdministratorRights(p GetMyDefaultAdministratorRightsP) (ChatAdministratorRights, error) { + req := NewRequest[ChatAdministratorRights]("getMyDefaultAdministratorRights", p) + return req.Do(api) +} + +func (api *Api) GetAvailableGifts() (Gifts, error) { + req := NewRequest[Gifts]("getAvailableGifts", NoParams) + return req.Do(api) +} + +type SendGiftP struct { + UserID int `json:"user_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + GiftID string `json:"gift_id"` + PayForUpgrade bool `json:"pay_for_upgrade"` + Text string `json:"text"` + TextParseMode ParseMode `json:"text_parse_mode,omitempty"` + TextEntities []MessageEntity `json:"text_entities,omitempty"` +} + +func (api *Api) SendGift(p SendGiftP) (bool, error) { + req := NewRequest[bool]("sendGift", p) + return req.Do(api) +} + +type GiftPremiumSubscriptionP struct { + UserID int `json:"user_id"` + MonthCount int `json:"month_count"` + StarCount int `json:"star_count"` + Text string `json:"text,omitempty"` + TextParseMode ParseMode `json:"text_parse_mode,omitempty"` + TextEntities []MessageEntity `json:"text_entities,omitempty"` +} + +func (api *Api) GiftPremiumSubscription(p GiftPremiumSubscriptionP) (bool, error) { + req := NewRequest[bool]("giftPremiumSubscription", p) + return req.Do(api) +} diff --git a/tgapi/bot_types.go b/tgapi/bot_types.go new file mode 100644 index 0000000..512bbdf --- /dev/null +++ b/tgapi/bot_types.go @@ -0,0 +1,99 @@ +package tgapi + +type BotCommand struct { + Command string `json:"command"` + Description string `json:"description"` +} +type BotCommandScopeType string + +const ( + BotCommandScopeDefaultType BotCommandScopeType = "default" + BotCommandScopePrivateType BotCommandScopeType = "all_private_chats" + BotCommandScopeGroupType BotCommandScopeType = "all_groups_chats" + BotCommandScopeAllChatAdministratorsType BotCommandScopeType = "all_chat_administrators" + BotCommandScopeChatType BotCommandScopeType = "chat" + BotCommandScopeChatAdministratorsType BotCommandScopeType = "chat_administrators" + BotCommandScopeChatMemberType BotCommandScopeType = "chat_member" +) + +type BaseBotCommandScope struct { + Type BotCommandScopeType `json:"type"` +} +type BotCommandScopeDefault struct { + BaseBotCommandScope +} +type BotCommandScopePrivateChats struct { + BaseBotCommandScope +} +type BotCommandScopeAllGroupChats struct { + BaseBotCommandScope +} +type BotCommandScopeAllChatAdministrators struct { + BaseBotCommandScope +} +type BotCommandScopeChat struct { + BaseBotCommandScope + ChatID int `json:"chat_id"` +} +type BotCommandScopeChatAdministrators struct { + BaseBotCommandScope + ChatID int `json:"chat_id"` +} +type BotCommandScopeChatMember struct { + BaseBotCommandScope + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` +} + +type BotName struct { + Name string `json:"name"` +} +type BotDescription struct { + Description string `json:"description"` +} +type BotShortDescription struct { + ShortDescription string `json:"short_description"` +} + +const ( + InputProfilePhotoStaticType InputProfilePhotoType = "static" + InputProfilePhotoAnimatedType InputProfilePhotoType = "animated" +) + +type InputProfilePhotoType string +type InputProfilePhoto interface { + InputProfilePhotoStatic | InputProfilePhotoAnimated +} +type BaseInputProfilePhoto struct { + Type InputProfilePhotoType `json:"type"` +} +type InputProfilePhotoStatic struct { + BaseInputProfilePhoto + Photo string `json:"photo"` +} +type InputProfilePhotoAnimated struct { + BaseInputProfilePhoto + Animation string `json:"animation"` + MainFrameTimestamp float64 `json:"main_frame_timestamp"` +} + +const ( + MenuButtonCommandsType MenuButtonType = "commands" + MenuButtonWebAppType MenuButtonType = "web_app" + MenuButtonDefaultType MenuButtonType = "default" +) + +type MenuButtonType string +type MenuButton interface { + MenuButtonCommands | MenuButtonDefault | MenuButtonWebApp +} +type BaseMenuButton struct { + Type MenuButtonType `json:"type"` +} +type MenuButtonCommands struct{ BaseMenuButton } +type MenuButtonDefault struct{ BaseMenuButton } +type MenuButtonWebApp struct { + BaseMenuButton + Text string `json:"text"` + WebApp WebAppInfo `json:"web_app"` +} diff --git a/tgapi/business_methods.go b/tgapi/business_methods.go new file mode 100644 index 0000000..2c9ee47 --- /dev/null +++ b/tgapi/business_methods.go @@ -0,0 +1,149 @@ +package tgapi + +type VerifyUserP struct { + UserID int `json:"user_id"` + CustomDescription string `json:"custom_description,omitempty"` +} + +func (api *Api) VerifyUser(p VerifyUserP) (bool, error) { + req := NewRequest[bool]("verifyUser", p) + return req.Do(api) +} + +type VerifyChatP struct { + ChatID int `json:"chat_id"` + CustomDescription string `json:"custom_description,omitempty"` +} + +func (api *Api) VerifyChat(p VerifyChatP) (bool, error) { + req := NewRequest[bool]("verifyChat", p) + return req.Do(api) +} + +type RemoveUserVerificationP struct { + UserID int `json:"user_id"` +} + +func (api *Api) RemoveUserVerification(p RemoveUserVerificationP) (bool, error) { + req := NewRequest[bool]("removeUserVerification", p) + return req.Do(api) +} + +type RemoveChatVerificationP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) RemoveChatVerification(p RemoveChatVerificationP) (bool, error) { + req := NewRequest[bool]("removeChatVerification", p) + return req.Do(api) +} + +type ReadBusinessMessageP struct { + BusinessConnectionID string `json:"business_connection_id"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` +} + +func (api *Api) ReadBusinessMessage(p ReadBusinessMessageP) (bool, error) { + req := NewRequest[bool]("readBusinessMessage", p) + return req.Do(api) +} + +type DeleteBusinessMessageP struct { + BusinessConnectionID string `json:"business_connection_id"` + MessageIDs []int `json:"message_ids"` +} + +func (api *Api) DeleteBusinessMessage(p DeleteBusinessMessageP) (bool, error) { + req := NewRequest[bool]("deleteBusinessMessage", p) + return req.Do(api) +} + +type SetBusinessAccountNameP struct { + BusinessConnectionID string `json:"business_connection_id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name,omitempty"` +} + +func (api *Api) SetBusinessAccountName(p SetBusinessAccountNameP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountName", p) + return req.Do(api) +} + +type SetBusinessAccountUsernameP struct { + BusinessConnectionID string `json:"business_connection_id"` + Username string `json:"username,omitempty"` +} + +func (api *Api) SetBusinessAccountUsername(p SetBusinessAccountUsernameP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountUsername", p) + return req.Do(api) +} + +type SetBusinessAccountBioP struct { + BusinessConnectionID string `json:"business_connection_id"` + Bio string `json:"bio,omitempty"` +} + +func (api *Api) SetBusinessAccountBio(p SetBusinessAccountBioP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountBio", p) + return req.Do(api) +} + +type SetBusinessAccountProfilePhoto[T InputProfilePhoto] struct { + BusinessConnectionID string `json:"business_connection_id"` + Photo T `json:"photo,omitempty"` + IsPublic bool `json:"is_public,omitempty"` +} + +func (api *Api) SetBusinessAccountProfilePhotoStatic(p SetMyProfilePhotoP[InputProfilePhotoStatic]) (bool, error) { + req := NewRequest[bool]("setBusinessAccountProfilePhoto", p) + return req.Do(api) +} +func (api *Api) SetBusinessAccountProfilePhotoAnimated(p SetMyProfilePhotoP[InputProfilePhotoAnimated]) (bool, error) { + req := NewRequest[bool]("setBusinessAccountProfilePhoto", p) + return req.Do(api) +} + +type RemoveBusinessAccountProfilePhotoP struct { + BusinessConnectionID string `json:"business_connection_id"` + IsPublic bool `json:"is_public,omitempty"` +} + +func (api *Api) RemoveBusinessAccountProfilePhoto(p RemoveBusinessAccountProfilePhotoP) (bool, error) { + req := NewRequest[bool]("removeBusinessAccountProfilePhoto", p) + return req.Do(api) +} + +type SetBusinessAccountGiftSettingsP struct { + BusinessConnectionID string `json:"business_connection_id"` + ShowGiftButton bool `json:"show_gift_button"` + AcceptedGiftTypes AcceptedGiftTypes `json:"accepted_gift_types"` +} + +func (api *Api) SetBusinessAccountGiftSettings(p SetBusinessAccountGiftSettingsP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountGiftSettings", p) + return req.Do(api) +} + +type GetBusinessAccountStarBalanceP struct { + BusinessConnectionID string `json:"business_connection_id"` +} + +func (api *Api) GetBusinessAccountStarBalance(p GetBusinessAccountStarBalanceP) (StarAmount, error) { + req := NewRequest[StarAmount]("getBusinessAccountGiftSettings", p) + return req.Do(api) +} + +type TransferBusinessAccountStartP struct { + BusinessConnectionID string `json:"business_connection_id"` + StarCount int `json:"star_count"` +} + +func (api *Api) TransferBusinessAccountStart(p TransferBusinessAccountStartP) (bool, error) { + req := NewRequest[bool]("transferBusinessAccountStart", p) + return req.Do(api) +} + +type GetBusinessAccountGiftsP struct { +} diff --git a/tgapi/business_types.go b/tgapi/business_types.go new file mode 100644 index 0000000..4f952de --- /dev/null +++ b/tgapi/business_types.go @@ -0,0 +1,44 @@ +package tgapi + +type BusinessIntro struct { + Title string `json:"title,omitempty"` + Message string `json:"message,omitempty"` + Sticker *Sticker `json:"sticker,omitempty"` +} +type BusinessLocation struct { + Address string `json:"address"` + Location *Location `json:"location,omitempty"` +} +type BusinessOpeningHoursInterval struct { + OpeningMinute int `json:"opening_minute"` + ClosingMinute int `json:"closing_minute"` +} +type BusinessOpeningHours struct { + TimeZoneName string `json:"time_zone_name"` + OpeningHours []Birthdate `json:"opening_hours"` +} + +type BusinessBotRights struct { + CanReply *bool `json:"can_reply,omitempty"` + CanReadMessages *bool `json:"can_read_messages,omitempty"` + CanDeleteSentMessages *bool `json:"can_delete_sent_messages,omitempty"` + CanDeleteAllMessages *bool `json:"can_delete_all_messages,omitempty"` + CanEditName *bool `json:"can_edit_name,omitempty"` + CanEditBio *bool `json:"can_edit_bio,omitempty"` + CanEditProfilePhoto *bool `json:"can_edit_profile_photo,omitempty"` + CanEditUsername *bool `json:"can_edit_username,omitempty"` + CanChangeGiftSettings *bool `json:"can_change_gift_settings,omitempty"` + CanViewGiftsAndStars *bool `json:"can_view_gifts_and_stars,omitempty"` + CanConvertGiftsToStars *bool `json:"can_convert_gifts_to_stars,omitempty"` + CanTransferAndUpgradeGifts *bool `json:"can_transfer_and_upgrade_gifts,omitempty"` + CanTransferStars *bool `json:"can_transfer_stars,omitempty"` + CanManageStories *bool `json:"can_manage_stories,omitempty"` +} +type BusinessConnection struct { + ID string `json:"id"` + User User `json:"user"` + UserChatID int `json:"user_chat_id"` + Date int `json:"date"` + Rights *BusinessBotRights `json:"rights,omitempty"` + IsEnabled bool `json:"id_enabled"` +} diff --git a/tgapi/chat_methods.go b/tgapi/chat_methods.go new file mode 100644 index 0000000..f6f4df5 --- /dev/null +++ b/tgapi/chat_methods.go @@ -0,0 +1,337 @@ +package tgapi + +type BanChatMemberP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + UntilDate int64 `json:"until_date,omitempty"` + RevokeMessages bool `json:"revoke_messages,omitempty"` +} + +func (api *Api) BanChatMember(p BanChatMemberP) (bool, error) { + req := NewRequest[bool]("banChatMember", p) + return req.Do(api) +} + +type UnbanChatMemberP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + OnlyIfBanned bool `json:"only_if_banned"` +} + +func (api *Api) UnbanChatMember(p UnbanChatMemberP) (bool, error) { + req := NewRequest[bool]("unbanChatMember", p) + return req.Do(api) +} + +type RestrictChatMemberP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + Permissions ChatPermissions `json:"permissions"` + UseIndependentChatPermissions bool `json:"use_independent_chat_permissions,omitempty"` + UntilDate int `json:"until_date,omitempty"` +} + +func (api *Api) RestrictChatMember(p RestrictChatMemberP) (bool, error) { + req := NewRequest[bool]("restrictChatMember", p) + return req.Do(api) +} + +type PromoteChatMember struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + IsAnonymous bool `json:"is_anonymous,omitempty"` + + CanManageChat bool `json:"can_manage_chat,omitempty"` + CanDeleteMessages bool `json:"can_delete_messages,omitempty"` + CanManageVideoChats bool `json:"can_manage_video_chats,omitempty"` + CanRestrictMembers bool `json:"can_restrict_members,omitempty"` + CanPromoteMembers bool `json:"can_promote_members,omitempty"` + CanChangeInfo bool `json:"can_change_info,omitempty"` + CanInviteUsers bool `json:"can_invite_users,omitempty"` + CanPostStories bool `json:"can_post_stories,omitempty"` + CanEditStories bool `json:"can_edit_stories,omitempty"` + CanDeleteStories bool `json:"can_delete_stories,omitempty"` + CanPostMessages bool `json:"can_post_messages,omitempty"` + CanEditMessages bool `json:"can_edit_messages,omitempty"` + CanPinMessages bool `json:"can_pin_messages,omitempty"` + CanManageTopics bool `json:"can_manage_topics,omitempty"` + CanManageDirectMessages bool `json:"can_manage_direct_messages,omitempty"` +} + +func (api *Api) PromoteChatMember(p PromoteChatMember) (bool, error) { + req := NewRequest[bool]("promoteChatMember", p) + return req.Do(api) +} + +type SetChatAdministratorCustomTitleP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + CustomTitle string `json:"custom_title"` +} + +func (api *Api) SetChatAdministratorCustomTitle(p SetChatAdministratorCustomTitleP) (bool, error) { + req := NewRequest[bool]("setChatAdministratorCustomTitle", p) + return req.Do(api) +} + +type BanChatSenderChatP struct { + ChatID int `json:"chat_id"` + SenderChatID int `json:"sender_chat_id"` +} + +func (api *Api) BanChatSenderChat(p BanChatSenderChatP) (bool, error) { + req := NewRequest[bool]("banChatSenderChat", p) + return req.Do(api) +} + +type UnbanChatSenderChatP struct { + ChatID int `json:"chat_id"` + SenderChatID int `json:"sender_chat_id"` +} + +func (api *Api) UnbanChatSenderChat(p BanChatSenderChatP) (bool, error) { + req := NewRequest[bool]("unbanChatSenderChat", p) + return req.Do(api) +} + +type SetChatPermissionsP struct { + ChatID int `json:"chat_id"` + Permissions ChatPermissions `json:"permissions"` + UseIndependentChatPermissions bool `json:"use_independent_chat_permissions,omitempty"` +} + +func (api *Api) SetChatPermissions(p SetChatPermissionsP) (bool, error) { + req := NewRequest[bool]("setChatPermissions", p) + return req.Do(api) +} + +type ExportChatInviteLinkP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) ExportChatInviteLink(p ExportChatInviteLinkP) (string, error) { + req := NewRequest[string]("exportChatInviteLink", p) + return req.Do(api) +} + +type CreateChatInviteLinkP struct { + ChatID int `json:"chat_id"` + Name string `json:"name,omitempty"` + ExpireDate int `json:"expire_date,omitempty"` + MemberLimit int `json:"member_limit,omitempty"` + CreatesJoinRequest int `json:"creates_join_request,omitempty"` +} + +func (api *Api) CreateChatInviteLink(p CreateChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("createChatInviteLink", p) + return req.Do(api) +} + +type EditChatInviteLinkP struct { + ChatID int `json:"chat_id"` + InviteLink string `json:"invite_link"` + + Name string `json:"name,omitempty"` + ExpireDate int `json:"expire_date,omitempty"` + MemberLimit int `json:"member_limit,omitempty"` + CreatesJoinRequest int `json:"creates_join_request,omitempty"` +} + +func (api *Api) EditChatInviteLink(p EditChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("editChatInviteLink", p) + return req.Do(api) +} + +type CreateChatSubscriptionInviteLinkP struct { + ChatID int `json:"chat_id"` + Name string `json:"name,omitempty"` + SubscriptionPeriod int `json:"subscription_period,omitempty"` + SubscriptionPrice int `json:"subscription_price,omitempty"` +} + +func (api *Api) CreateChatSubscriptionInviteLink(p CreateChatSubscriptionInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("createChatSubscriptionInviteLink", p) + return req.Do(api) +} + +type EditChatSubscriptionInviteLinkP struct { + ChatID int `json:"chat_id"` + InviteLink string `json:"invite_link"` + Name string `json:"name,omitempty"` +} + +func (api *Api) EditChatSubscriptionInviteLink(p EditChatSubscriptionInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("editChatSubscriptionInviteLink", p) + return req.Do(api) +} + +type RevokeChatInviteLinkP struct { + ChatID int `json:"chat_id"` + InviteLink string `json:"invite_link"` +} + +func (api *Api) RevokeChatInviteLink(p RevokeChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("revokeChatInviteLink", p) + return req.Do(api) +} + +type ApproveChatJoinRequestP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` +} + +func (api *Api) ApproveChatJoinRequest(p ApproveChatJoinRequestP) (bool, error) { + req := NewRequest[bool]("approveChatJoinRequest", p) + return req.Do(api) +} + +type DeclineChatJoinRequestP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` +} + +func (api *Api) DeclineChatJoinRequest(p DeclineChatJoinRequestP) (bool, error) { + req := NewRequest[bool]("declineChatJoinRequest", p) + return req.Do(api) +} + +func (api *Api) SetChatPhoto() { + uploader := NewUploader(api) + defer uploader.Close() +} + +type DeleteChatPhotoP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) DeleteChatPhoto(p DeleteChatPhotoP) (bool, error) { + req := NewRequest[bool]("deleteChatPhoto", p) + return req.Do(api) +} + +type SetChatTitleP struct { + ChatID int `json:"chat_id"` + Title string `json:"title"` +} + +func (api *Api) SetChatTitle(p SetChatTitleP) (bool, error) { + req := NewRequest[bool]("setChatTitle", p) + return req.Do(api) +} + +type SetChatDescriptionP struct { + ChatID int `json:"chat_id"` + Description string `json:"description"` +} + +func (api *Api) SetChatDescription(p SetChatDescriptionP) (bool, error) { + req := NewRequest[bool]("setChatDescription", p) + return req.Do(api) +} + +type PinChatMessageP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + DisableNotification bool `json:"disable_notification,omitempty"` +} + +func (api *Api) PinChatMessage(p PinChatMessageP) (bool, error) { + req := NewRequest[bool]("pinChatMessage", p) + return req.Do(api) +} + +type UnpinChatMessageP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` +} + +func (api *Api) UnpinChatMessage(p UnpinChatMessageP) (bool, error) { + req := NewRequest[bool]("unpinChatMessage", p) + return req.Do(api) +} + +type UnpinAllChatMessagesP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) UnpinAllChatMessages(p UnpinAllChatMessagesP) (bool, error) { + req := NewRequest[bool]("unpinAllChatMessages", p) + return req.Do(api) +} + +type LeaveChatP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) LeaveChat(p LeaveChatP) (bool, error) { + req := NewRequest[bool]("leaveChatP", p) + return req.Do(api) +} + +type GetChatP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) GetChatP(p GetChatP) (ChatFullInfo, error) { + req := NewRequest[ChatFullInfo]("getChatP", p) + return req.Do(api) +} + +type GetChatAdministratorsP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) GetChatAdministrators(p GetChatAdministratorsP) ([]BaseChatMember, error) { + req := NewRequest[[]BaseChatMember]("getChatAdministrators", p) + return req.Do(api) +} + +type GetChatMembersCountP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) GetChatMemberCount(p GetChatMembersCountP) (int, error) { + req := NewRequest[int]("getChatMemberCount", p) + return req.Do(api) +} + +type GetChatMemberP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` +} + +func (api *Api) GetChatMember(p GetChatMemberP) (BaseChatMember, error) { + req := NewRequest[BaseChatMember]("getChatMember", p) + return req.Do(api) +} + +type SetChatStickerSetP struct { + ChatID int `json:"chat_id"` + StickerSetName string `json:"sticker_set_name"` +} + +func (api *Api) SetChatStickerSet(p SetChatStickerSetP) (bool, error) { + req := NewRequest[bool]("setChatStickerSet", p) + return req.Do(api) +} + +type DeleteChatStickerSetP struct { + ChatID int `json:"chat_id"` +} + +func (api *Api) DeleteChatStickerSet(p DeleteChatStickerSetP) (bool, error) { + req := NewRequest[bool]("deleteChatStickerSet", p) + return req.Do(api) +} + +type GetUserChatBoostsP struct { + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` +} + +func (api *Api) GetUserChatBoosts(p GetUserChatBoostsP) (UserChatBoosts, error) { + req := NewRequest[UserChatBoosts]("getUserChatBoosts", p) + return req.Do(api) +} diff --git a/tgapi/chat_types.go b/tgapi/chat_types.go new file mode 100644 index 0000000..1983699 --- /dev/null +++ b/tgapi/chat_types.go @@ -0,0 +1,242 @@ +package tgapi + +type Chat struct { + ID int `json:"id"` + Type string `json:"type"` + Title *string `json:"title,omitempty"` + Username *string `json:"username,omitempty"` + FirstName *string `json:"first_name,omitempty"` + LastName *string `json:"last_name,omitempty"` + IsForum *bool `json:"is_forum,omitempty"` + IsDirectMessages *bool `json:"is_direct_messages,omitempty"` +} + +type ChatType string + +const ( + ChatTypePrivate ChatType = "private" + ChatTypeGroup ChatType = "group" + ChatTypeSupergroup ChatType = "supergroup" + ChatTypeChannel ChatType = "channel" +) + +type ChatFullInfo struct { + ID int `json:"id"` + Type ChatType `json:"type"` + Title string `json:"title"` + Username string `json:"username"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + IsForum bool `json:"is_forum"` + IsDirectMessages bool `json:"is_direct_messages"` + AccentColorID int `json:"accent_color_id"` + MaxReactionCount int `json:"max_reaction_count"` + Photo *ChatPhoto `json:"photo,omitempty"` + ActiveUsernames []string `json:"active_usernames,omitempty"` + Birthdate *Birthdate `json:"birthdate,omitempty"` + + BusinessIntro *BusinessIntro `json:"business_intro,omitempty"` + BusinessLocation *BusinessLocation `json:"business_location,omitempty"` + BusinessOpeningHours *BusinessOpeningHours `json:"business_opening_hours,omitempty"` + + PersonalChat *Chat `json:"personal_chat,omitempty"` + ParentChat *Chat `json:"parent_chat,omitempty"` + + AvailableReaction []BaseReaction `json:"available_reaction,omitempty"` + + BackgroundCustomEmojiID *string `json:"background_custom_emoji_id,omitempty"` + ProfileAccentColorID *int `json:"profile_accent_color_id,omitempty"` + ProfileBackgroundCustomEmojiID *string `json:"profile_background_custom_emoji_id,omitempty"` + EmojiStatusCustomEmojiID *string `json:"emoji_status_custom_emoji_id,omitempty"` + EmojiStatusExpirationDate *int `json:"emoji_status_expiration_date,omitempty"` + + Bio *string `json:"bio,omitempty"` + HasPrivateForwards *bool `json:"has_private_forwards,omitempty"` + HasRestrictedVoiceAndVideoMessages *bool `json:"has_restricted_voice_and_video_messages,omitempty"` + JoinToSendMessages *bool `json:"join_to_send_messages,omitempty"` + JoinByRequest *bool `json:"join_by_request,omitempty"` + + Description *string `json:"description,omitempty"` + InviteLink *string `json:"invite_link,omitempty"` + PinnedMessage *Message `json:"pinned_message,omitempty"` + Permissions *ChatPermissions `json:"permissions,omitempty"` + AcceptedGiftTypes *AcceptedGiftTypes `json:"accepted_gift_types,omitempty"` + + CanSendPaidMedia *bool `json:"can_send_paid_media,omitempty"` + SlowModeDelay *int `json:"slow_mode_delay,omitempty"` + UnrestrictedBoostCount *int `json:"unrestricted_boost_count,omitempty"` + MessageAutoDeleteTime *int `json:"message_auto_delete_time,omitempty"` + HasAggressiveAntiSpamEnabled *bool `json:"has_aggressive_anti_spam_enabled,omitempty"` + HasHiddenMembers *bool `json:"has_hidden_members,omitempty"` + HasProtectedContent *bool `json:"has_protected_content,omitempty"` + HasVisibleHistory *bool `json:"has_visible_history,omitempty"` + StickerSetName *string `json:"sticker_set_name,omitempty"` + CanSetStickerSet *bool `json:"can_set_sticker_set,omitempty"` + CustomEmojiStickerSetName *string `json:"custom_emoji_sticker_set_name,omitempty"` + LinkedChatID *int `json:"linked_chat_id,omitempty"` + + Location *ChatLocation `json:"location,omitempty"` + Rating *UserRating `json:"rating,omitempty"` + FirstProfileAudio *Audio `json:"first_profile_audio,omitempty"` + UniqueGiftColors *UniqueGiftColors `json:"unique_gift_colors,omitempty"` + PaidMessageStarCount *int `json:"paid_message_star_count,omitempty"` +} + +type ChatPhoto struct { + SmallFileID string `json:"small_file_id"` + SmallFileUniqueID string `json:"small_file_unique_id"` + BigFileID string `json:"big_file_id"` + BigFileUniqueID string `json:"big_file_unique_id"` +} + +type ChatPermissions struct { + CanSendMessages bool `json:"can_send_messages"` + CanSendAudios bool `json:"can_send_audios"` + CanSendDocuments bool `json:"can_send_documents"` + CanSendPhotos bool `json:"can_send_photos"` + CanSendVideoNotes bool `json:"can_send_video_notes"` + CanSendVoiceNotes bool `json:"can_send_voice_notes"` + CanSendPolls bool `json:"can_send_polls"` + CanSendOtherMessages bool `json:"can_send_other_messages"` + CanAddWebPagePreview bool `json:"can_add_web_page_preview"` + CanChangeInfo bool `json:"can_change_info"` + CanInviteUsers bool `json:"can_invite_users"` + CanPinMessages bool `json:"can_pin_messages"` + CanManageTopics bool `json:"can_manage_topics"` +} +type ChatLocation struct { + Location Location `json:"location"` + Address string `json:"address"` +} +type ChatInviteLink struct { + InviteLink string `json:"invite_link"` + Creator User `json:"creator"` + CreateJoinRequest bool `json:"create_join_request"` + IsPrimary bool `json:"is_primary"` + IsRevoked bool `json:"is_revoked"` + + Name *string `json:"name,omitempty"` + ExpireDate *int `json:"expire_date,omitempty"` + MemberLimit *int `json:"member_limit,omitempty"` + PendingJoinRequestCount *int `json:"pending_join_request_count,omitempty"` + SubscriptionPeriod *int `json:"subscription_period,omitempty"` + SubscriptionPrice *int `json:"subscription_price,omitempty"` +} + +type ChatMemberStatusType string + +const ( + ChatMemberStatusOwner ChatMemberStatusType = "owner" + ChatMemberStatusAdministrator ChatMemberStatusType = "administrator" + ChatMemberStatusMember ChatMemberStatusType = "member" + ChatMemberStatusRestricted ChatMemberStatusType = "restricted" + ChatMemberStatusLeft ChatMemberStatusType = "left" + ChatMemberStatusBanned ChatMemberStatusType = "kicked" +) + +type ChatMember interface { + ChatMemberOwner | ChatMemberAdministrator | ChatMemberMember | ChatMemberRestricted | ChatMemberLeft | ChatMemberBanned +} +type BaseChatMember struct { + Status ChatMemberStatusType `json:"status"` + User User `json:"user"` +} +type ChatMemberOwner struct { + BaseChatMember + + IsAnonymous bool `json:"is_anonymous"` + CustomTitle *string `json:"custom_title,omitempty"` +} +type ChatMemberAdministrator struct { + BaseChatMember + CanBeEdited bool `json:"can_be_edited"` + IsAnonymous bool `json:"is_anonymous"` + CanManageChat bool `json:"can_manage_chat"` + CanDeleteMessages bool `json:"can_delete_messages"` + CanManageVideoChats bool `json:"can_manage_video_chats"` + CanRestrictMembers bool `json:"can_restrict_members"` + CanPromoteMembers bool `json:"can_promote_members"` + CanChangeInfo bool `json:"can_change_info"` + CanInviteUsers bool `json:"can_invite_users"` + CanPostStories bool `json:"can_post_stories"` + CanEditStories bool `json:"can_edit_stories"` + CanDeleteStories bool `json:"can_delete_stories"` + + CanPostMessages *bool `json:"can_post_messages,omitempty"` + CanEditMessages *bool `json:"can_edit_messages,omitempty"` + CanPinMessages *bool `json:"can_pin_messages,omitempty"` + CanManageTopics *bool `json:"can_manage_topics,omitempty"` + CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` + CustomTitle *string `json:"custom_title,omitempty"` +} +type ChatMemberMember struct { + BaseChatMember + UntilDate *int `json:"until_date,omitempty"` +} +type ChatMemberRestricted struct { + BaseChatMember + IsMember bool `json:"is_member"` + CanSendMessages bool `json:"can_send_messages"` + CanSendAudios bool `json:"can_send_audios"` + CanSendDocuments bool `json:"can_send_documents"` + CanSendVideos bool `json:"can_send_videos"` + CanSendVideoNotes bool `json:"can_send_video_notes"` + CanSendVoiceNotes bool `json:"can_send_voice_notes"` + CanSendPolls bool `json:"can_send_polls"` + CanSendOtherMessages bool `json:"can_send_other_messages"` + CanAddWebPagePreview bool `json:"can_add_web_page_preview"` + CanChangeInfo bool `json:"can_change_info"` + CanInviteUsers bool `json:"can_invite_users"` + CanPinMessages bool `json:"can_pin_messages"` + CanManageTopics bool `json:"can_manage_topics"` + UntilDate int `json:"until_date"` +} +type ChatMemberLeft struct { + BaseChatMember +} +type ChatMemberBanned struct { + BaseChatMember + UntilDate int `json:"until_date"` +} + +type BaseChatBoostSource struct { + Source string `json:"source"` + User User `json:"user"` +} +type ChatBoostSourcePremium struct{ BaseChatBoostSource } +type ChatBoostSourceGiftCode struct{ BaseChatBoostSource } +type ChatBoostSourceGiveaway struct { + BaseChatBoostSource + GiveawayMessageID int `json:"giveaway_message_id"` + PrizeStarCount *int `json:"prize_star_count,omitempty"` + IsUnclaimed bool `json:"is_unclaimed"` +} +type ChatBoost[T BaseChatBoostSource] struct { + BoostID int `json:"boost_id"` + AddDate int `json:"add_date"` + ExpirationDate int `json:"expiration_date"` + Source T `json:"source"` +} +type UserChatBoosts struct { + Boosts []ChatBoost[BaseChatBoostSource] `json:"boosts"` +} + +type ChatAdministratorRights struct { + IsAnonymous bool `json:"is_anonymous"` + CanManageChat bool `json:"can_manage_chat"` + CanDeleteMessages bool `json:"can_delete_messages"` + CanManageVideoChats bool `json:"can_manage_video_chats"` + CanRestrictMembers bool `json:"can_restrict_members"` + CanPromoteMembers bool `json:"can_promote_members"` + CanChangeInfo bool `json:"can_change_info"` + CanInviteUsers bool `json:"can_invite_users"` + CanPostStories bool `json:"can_post_stories"` + CanEditStories bool `json:"can_edit_stories"` + CanDeleteStories bool `json:"can_delete_stories"` + + CanPostMessages *bool `json:"can_post_messages,omitempty"` + CanEditMessages *bool `json:"can_edit_messages,omitempty"` + CanPinMessages *bool `json:"can_pin_messages,omitempty"` + CanManageTopics *bool `json:"can_manage_topics,omitempty"` + CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` +} diff --git a/tgapi/forum_methods.go b/tgapi/forum_methods.go new file mode 100644 index 0000000..48e31e2 --- /dev/null +++ b/tgapi/forum_methods.go @@ -0,0 +1,86 @@ +package tgapi + +type BaseForumTopicP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id"` +} + +func (api *Api) GetForumTopicIconSet() ([]Sticker, error) { + req := NewRequest[[]Sticker]("getForumTopicIconSet", NoParams) + return req.Do(api) +} + +type CreateForumTopicP struct { + ChatID int `json:"chat_id"` + Name string `json:"name"` + IconColor ForumTopicIconColor `json:"icon_color"` + IconCustomEmojiID string `json:"icon_custom_emoji_id"` +} + +func (api *Api) CreateForumTopic(p CreateForumTopicP) (ForumTopic, error) { + req := NewRequest[ForumTopic]("createForumTopic", p) + return req.Do(api) +} + +type EditForumTopicP struct { + BaseForumTopicP + Name string `json:"name"` + IconCustomEmojiID string `json:"icon_custom_emoji_id"` +} + +func (api *Api) EditForumTopic(p EditForumTopicP) (bool, error) { + req := NewRequest[bool]("editForumTopic", p) + return req.Do(api) +} + +func (api *Api) CloseForumTopic(p BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("closeForumTopic", p) + return req.Do(api) +} +func (api *Api) ReopenForumTopic(p BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("reopenForumTopic", p) + return req.Do(api) +} +func (api *Api) DeleteForumTopic(p BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("deleteForumTopic", p) + return req.Do(api) +} +func (api *Api) UnpinAllForumTopicMessages(p BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("unpinAllForumTopicMessages", p) + return req.Do(api) +} + +type BaseGeneralForumTopicP struct { + ChatID int `json:"chat_id"` +} + +type EditGeneralForumTopicP struct { + ChatID int `json:"chat_id"` + Name string `json:"name"` +} + +func (api *Api) EditGeneralForumTopic(p EditGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("editGeneralForumTopic", p) + return req.Do(api) +} + +func (api *Api) CloseGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("closeGeneralForumTopic", p) + return req.Do(api) +} +func (api *Api) ReopenGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("reopenGeneralForumTopic", p) + return req.Do(api) +} +func (api *Api) HideGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("hideGeneralForumTopic", p) + return req.Do(api) +} +func (api *Api) UnhideGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("unhideGeneralForumTopic", p) + return req.Do(api) +} +func (api *Api) UnpinAllGeneralForumTopicMessages(p BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("unpinAllGeneralForumTopicMessages", p) + return req.Do(api) +} diff --git a/tgapi/forum_types.go b/tgapi/forum_types.go new file mode 100644 index 0000000..45a4661 --- /dev/null +++ b/tgapi/forum_types.go @@ -0,0 +1,15 @@ +package tgapi + +type ForumTopic struct { + MessageThreadID int `json:"message_thread_id"` + Name string `json:"name"` + IconColor int `json:"icon_color"` + IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` + IsNameImplicit bool `json:"is_name_implicit,omitempty"` +} + +type ForumTopicIconColor int + +const ( + ForumTopicIconColorBlue ForumTopicIconColor = 7322096 +) diff --git a/tgapi/messages_methods.go b/tgapi/messages_methods.go new file mode 100644 index 0000000..e76d382 --- /dev/null +++ b/tgapi/messages_methods.go @@ -0,0 +1,367 @@ +package tgapi + +type SendMessageP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Entities []*MessageEntity `json:"entities,omitempty"` + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendMessage(params *SendMessageP) (Message, error) { + req := NewRequest[Message, SendMessageP]("sendMessage", *params) + return req.Do(api) +} + +type ForwardMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + MessageID int `json:"message_id,omitempty"` + FromChatID int `json:"from_chat_id,omitempty"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + + MessageEffectID string `json:"message_effect_id,omitempty"` + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` +} + +func (api *Api) ForwardMessage(params ForwardMessageP) (Message, error) { + req := NewRequest[Message]("forwardMessage", params) + return req.Do(api) +} + +type ForwardMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` +} + +func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) { + req := NewRequest[[]int]("forwardMessages", params) + return req.Do(api) +} + +type CopyMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id"` + MessageID int `json:"message_id"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) CopyMessage(params CopyMessageP) (int, error) { + req := NewRequest[int]("copyMessage", params) + return req.Do(api) +} + +type CopyMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + RemoveCaption bool `json:"remove_caption,omitempty"` +} + +func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) { + req := NewRequest[[]int]("copyMessages", params) + return req.Do(api) +} + +type SendLocationP struct { + BusinessConnectionID int `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` + LivePeriod int `json:"live_period,omitempty"` + Heading int `json:"heading,omitempty"` + ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendLocation(params SendLocationP) (Message, error) { + req := NewRequest[Message]("sendLocation", params) + return req.Do(api) +} + +type SendVenueP struct { + BusinessConnectionID int `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Title string `json:"title"` + Address string `json:"address"` + FoursquareID string `json:"foursquare_id,omitempty"` + FoursquareType string `json:"foursquare_type,omitempty"` + GooglePlaceID string `json:"google_place_id,omitempty"` + GooglePlaceType string `json:"google_place_type,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendVenue(params SendVenueP) (Message, error) { + req := NewRequest[Message]("sendVenue", params) + return req.Do(api) +} + +type SendContactP struct { + BusinessConnectionID int `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + PhoneNumber string `json:"phone_number"` + FirstName string `json:"first_name"` + LastName string `json:"last_name,omitempty"` + Vcard string `json:"vcard"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendContact(params SendContactP) (Message, error) { + req := NewRequest[Message]("sendContact", params) + return req.Do(api) +} + +type SendPollP struct { + BusinessConnectionID int `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + + Question string `json:"question"` + QuestionParseMode ParseMode `json:"question_mode,omitempty"` + QuestionEntities []*MessageEntity `json:"question_entities,omitempty"` + Options []InputPollOption `json:"options"` + IsAnonymous bool `json:"is_anonymous,omitempty"` + Type PollType `json:"type"` + AllowsMultipleAnswers bool `json:"allows_multiple_answers,omitempty"` + CorrectOptionID int `json:"correct_option_id,omitempty"` + Explanation string `json:"explanation,omitempty"` + ExplanationParseMode ParseMode `json:"explanation_parse_mode,omitempty"` + ExplanationEntities []*MessageEntity `json:"explanation_entities,omitempty"` + OpenPeriod int `json:"open_period,omitempty"` + CloseDate int `json:"close_date"` + IsClosed bool `json:"is_closed,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendPoll(params SendPollP) (Message, error) { + req := NewRequest[Message]("sendPoll", params) + return req.Do(api) +} + +type SendChecklistP struct { + BusinessConnectionID int `json:"business_connection_id"` + ChatID int `json:"chat_id"` + Checklist InputChecklist `json:"checklist"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendChecklist(params SendChecklistP) (Message, error) { + req := NewRequest[Message]("sendChecklist", params) + return req.Do(api) +} + +type SendDiceP struct { + BusinessConnectionID int `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Emoji string `json:"emoji,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) SendDice(params SendDiceP) (Message, error) { + req := NewRequest[Message]("sendDice", params) + return req.Do(api) +} + +type SendMessageDraftP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DraftID int `json:"draft_id"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Entities []*MessageEntity `json:"entities,omitempty"` +} + +func (api *Api) SendMessageDraft(params SendMessageDraftP) (bool, error) { + req := NewRequest[bool]("sendMessageDraft", params) + return req.Do(api) +} + +type SendChatActionP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + Action ChatActionType `json:"action"` +} + +func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { + req := NewRequest[bool]("sendChatAction", params) + return req.Do(api) +} + +type SetMessageReactionP[T ReactionType] struct { + ChatId int `json:"chat_id"` + MessageId int `json:"message_id"` + Reaction []T `json:"reaction"` + IsBig bool `json:"is_big,omitempty"` +} + +func (api *Api) SetMessageReactionEmoji(params SetMessageReactionP[ReactionTypeEmoji]) (bool, error) { + req := NewRequest[bool]("setMessageReaction", params) + return req.Do(api) +} +func (api *Api) SetMessageReactionCustom(params SetMessageReactionP[ReactionTypeCustomEmoji]) (bool, error) { + req := NewRequest[bool]("setMessageReaction", params) + return req.Do(api) +} +func (api *Api) SetMessageReactionPaid(params SetMessageReactionP[ReactionTypePaid]) (bool, error) { + req := NewRequest[bool]("setMessageReaction", params) + return req.Do(api) +} + +// Message update methods + +type EditMessageTextP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) EditMessageText(params *EditMessageTextP) (Message, error) { + req := NewRequest[Message]("editMessageText", params) + return req.Do(api) +} + +type EditMessageCaptionP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Caption string `json:"caption"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (Message, error) { + req := NewRequest[Message]("editMessageCaption", params) + return req.Do(api) +} + +type DeleteMessageP struct { + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` +} + +func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) { + req := NewRequest[bool]("deleteMessage", params) + return req.Do(api) +} + +type AnswerCallbackQueryP struct { + CallbackQueryID string `json:"callback_query_id"` + Text string `json:"text,omitempty"` + ShowAlert bool `json:"show_alert,omitempty"` + URL string `json:"url,omitempty"` + CacheTime int `json:"cache_time,omitempty"` +} + +func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { + req := NewRequest[bool]("answerCallbackQuery", params) + return req.Do(api) +} diff --git a/types.go b/tgapi/messages_types.go similarity index 58% rename from types.go rename to tgapi/messages_types.go index 781b260..1bb7727 100644 --- a/types.go +++ b/tgapi/messages_types.go @@ -1,49 +1,4 @@ -package laniakea - -import "git.nix13.pw/scuroneko/extypes" - -type Update struct { - UpdateID int `json:"update_id"` - Message *Message `json:"message"` - EditedMessage *Message `json:"edited_message,omitempty"` - ChannelPost *Message `json:"channel_post,omitempty"` - EditedChannelPost *Message `json:"edited_channel_post,omitempty"` - BusinessConnection *BusinessConnection `json:"business_connection,omitempty"` - BusinessMessage *Message `json:"business_message,omitempty"` - EditedBusinessMessage *Message `json:"edited_business_message,omitempty"` - DeletedBusinessMessage *Message `json:"deleted_business_messages,omitempty"` - MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"` - MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"` - CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` - InlineQuery int - ChosenInlineResult int -} - -type User struct { - ID int `json:"id"` - IsBot bool `json:"is_bot"` - FirstName string `json:"first_name"` - LastName string `json:"last_name,omitempty"` - Username string `json:"username,omitempty"` - LanguageCode string `json:"language_code,omitempty"` - IsPremium bool `json:"is_premium,omitempty"` - AddedToAttachmentMenu bool `json:"added_to_attachment_menu,omitempty"` - CanJoinGroups bool `json:"can_join_groups,omitempty"` - CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"` - SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"` - CanConnectToBusiness bool `json:"can_connect_to_business,omitempty"` - HasMainWebApp bool `json:"has_main_web_app,omitempty"` -} - -type Chat struct { - ID int `json:"id"` - Type string `json:"type"` - Title string `json:"title,omitempty"` - Username string `json:"username,omitempty"` - FirstName string `json:"first_name,omitempty"` - LastName string `json:"last_name,omitempty"` - IsForum bool `json:"is_forum,omitempty"` -} +package tgapi type MessageReplyMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` @@ -71,9 +26,9 @@ type Message struct { Text string `json:"text"` - Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Photo []*PhotoSize `json:"photo,omitempty"` + Caption string `json:"caption,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` Date int `json:"date"` EditDate int `json:"edit_date"` @@ -87,14 +42,13 @@ type Message struct { EffectID string `json:"effect_id,omitempty"` } -type InaccessableMessage struct { - Chat *Chat `json:"chat"` - MessageID int `json:"message_id"` - Date int `json:"date"` +type InaccessibleMessage struct { + Chat Chat `json:"chat"` + MessageID int `json:"message_id"` + Date int `json:"date"` } -type MaybeInaccessibleMessage struct { -} +type MaybeInaccessibleMessage interface{ Message | InaccessibleMessage } type MessageEntityType string @@ -122,7 +76,7 @@ const ( type MessageEntity struct { Type MessageEntityType `json:"type"` - + Offset int `json:"offset"` Length int `json:"length"` URL string `json:"url,omitempty"` @@ -143,14 +97,6 @@ type ReplyParameters struct { ChecklistTaskID int `json:"checklist_task_id,omitempty"` } -type PhotoSize struct { - FileID string `json:"file_id"` - FileUniqueID string `json:"file_unique_id"` - Width int `json:"width"` - Height int `json:"height"` - FileSize int `json:"file_size,omitempty"` -} - type LinkPreviewOptions struct { IsDisabled bool `json:"is_disabled,omitempty"` URL string `json:"url,omitempty"` @@ -191,30 +137,61 @@ type ReplyKeyboardMarkup struct { } type CallbackQuery struct { - ID string `json:"id"` - From *User `json:"from"` - Message *Message `json:"message"` + ID string `json:"id"` + From User `json:"from"` + Message Message `json:"message"` Data string `json:"data"` } -type BusinessConnection struct { - ID string `json:"id"` - User *User `json:"user"` - UserChatID int `json:"user_chat_id"` - Date int `json:"date"` - CanReply bool `json:"can_reply"` - IsEnabled bool `json:"id_enabled"` +type InputPollOption struct { + Text string `json:"text"` + TextParseMode ParseMode `json:"text_parse_mode,omitempty"` + TextEntities []*MessageEntity `json:"text_entities,omitempty"` +} +type PollType string + +const ( + PollTypeRegular PollType = "regular" + PollTypeQuiz PollType = "quiz" +) + +type InputChecklistTask struct { + ID int `json:"id"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + TextEntities []*MessageEntity `json:"text_entities,omitempty"` +} +type InputChecklist struct { + Title string `json:"title"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + TitleEntities []*MessageEntity `json:"title_entities,omitempty"` + Tasks []InputChecklistTask `json:"tasks"` + OtherCanAddTasks bool `json:"other_can_add_tasks,omitempty"` + OtherCanMarkTasksAsDone bool `json:"other_can_mark_tasks_as_done,omitempty"` } +type ChatActionType string + +const ( + ChatActionTyping ChatActionType = "typing" + ChatActionUploadPhoto ChatActionType = "upload_photo" + ChatActionUploadVideo ChatActionType = "upload_video" + ChatActionUploadVoice ChatActionType = "upload_voice" + ChatActionUploadDocument ChatActionType = "upload_document" + ChatActionChooseSticker ChatActionType = "choose_sticker" + ChatActionFindLocation ChatActionType = "find_location" + ChatActionUploadVideoNone ChatActionType = "upload_video_none" +) + type MessageReactionUpdated struct { - Chat *Chat `json:"chat"` - MessageID int `json:"message_id"` - User *User `json:"user,omitempty"` - ActorChat *Chat `json:"actor_chat"` - Date int `json:"date"` - OldReaction []*ReactionType `json:"old_reaction"` - NewReaction []*ReactionType `json:"new_reaction"` + Chat *Chat `json:"chat"` + MessageID int `json:"message_id"` + User *User `json:"user,omitempty"` + ActorChat *Chat `json:"actor_chat"` + Date int `json:"date"` + OldReaction []BaseReaction `json:"old_reaction"` + NewReaction []BaseReaction `json:"new_reaction"` } type MessageReactionCountUpdated struct { @@ -224,45 +201,28 @@ type MessageReactionCountUpdated struct { Reactions []*ReactionCount `json:"reactions"` } -type ReactionType struct { +type ReactionType interface { + ReactionTypeEmoji | ReactionTypeCustomEmoji | ReactionTypePaid +} +type BaseReaction struct { Type string `json:"type"` } type ReactionTypeEmoji struct { - ReactionType + Type string `json:"type"` Emoji string `json:"emoji"` } type ReactionTypeCustomEmoji struct { - ReactionType + Type string `json:"type"` CustomEmojiID string `json:"custom_emoji_id"` } type ReactionTypePaid struct { - ReactionType + Type string `json:"type"` } type ReactionCount struct { - Type *ReactionType `json:"type"` - TotalCount int `json:"total_count"` + Type BaseReaction `json:"type"` + TotalCount int `json:"total_count"` } -type File struct { - FileId string `json:"file_id"` - FileUniqueID string `json:"file_unique_id"` - FileSize int `json:"file_size,omitempty"` - FilePath string `json:"file_path,omitempty"` -} - -type ChatActions string - -const ( - ChatActionTyping ChatActions = "typing" - ChatActionUploadPhoto ChatActions = "upload_photo" - ChatActionUploadVideo ChatActions = "upload_video" - ChatActionUploadVoice ChatActions = "upload_voice" - ChatActionUploadDocument ChatActions = "upload_document" - ChatActionChooseSticker ChatActions = "choose_sticker" - ChatActionFindLocation ChatActions = "find_location" - ChatActionUploadVideoNone ChatActions = "upload_video_none" -) - type SuggestedPostPrice struct { Currency string `json:"currency"` Amount int `json:"amount"` diff --git a/tgapi/methods.go b/tgapi/methods.go new file mode 100644 index 0000000..b000089 --- /dev/null +++ b/tgapi/methods.go @@ -0,0 +1,41 @@ +package tgapi + +type ParseMode string + +const ( + ParseMDV2 ParseMode = "MarkdownV2" + ParseHTML ParseMode = "HTML" + ParseMD ParseMode = "Markdown" +) + +type EmptyParams struct{} + +var NoParams = EmptyParams{} + +type UpdateParams struct { + Offset int `json:"offset"` + Timeout int `json:"timeout"` + AllowedUpdates []string `json:"allowed_updates"` +} + +func (api *Api) GetMe() (User, error) { + req := NewRequest[User, EmptyParams]("getMe", NoParams) + return req.Do(api) +} +func (api *Api) LogOut() (bool, error) { + req := NewRequest[bool, EmptyParams]("logOut", NoParams) + return req.Do(api) +} +func (api *Api) Close() (bool, error) { + req := NewRequest[bool, EmptyParams]("close", NoParams) + return req.Do(api) +} + +type GetFileP struct { + FileId string `json:"file_id"` +} + +func (api *Api) GetFile(params GetFileP) (File, error) { + req := NewRequest[File]("getFile", params) + return req.Do(api) +} diff --git a/tgapi/stickers_methods.go b/tgapi/stickers_methods.go new file mode 100644 index 0000000..f86977d --- /dev/null +++ b/tgapi/stickers_methods.go @@ -0,0 +1,166 @@ +package tgapi + +type SendStickerP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Sticker string `json:"sticker"` + Emoji string `json:"emoji,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` +} + +func (api *Api) SendSticker(p SendStickerP) (Message, error) { + req := NewRequest[Message]("sendSticker", p) + return req.Do(api) +} + +type GetStickerSetP struct { + Name string `json:"name"` +} + +func (api *Api) GetStickerSet(p GetStickerSetP) (StickerSet, error) { + req := NewRequest[StickerSet]("getStickerSet", p) + return req.Do(api) +} + +type GetCustomEmojiStickersP struct { + CustomEmojiIDs []string `json:"custom_emoji_ids"` +} + +func (api *Api) GetCustomEmojiStickers(p GetCustomEmojiStickersP) ([]Sticker, error) { + req := NewRequest[[]Sticker]("getCustomEmojiStickers", p) + return req.Do(api) +} + +type CreateNewStickerSetP struct { + UserID int `json:"user_id"` + Name string `json:"name"` + Title string `json:"title"` + + Stickers []InputSticker `json:"stickers"` + StickerType StickerType `json:"sticker_type,omitempty"` + NeedsRepainting bool `json:"needs_repainting,omitempty"` +} + +func (api *Api) CreateNewStickerSet(p CreateNewStickerSetP) (bool, error) { + req := NewRequest[bool]("createNewStickerSet", p) + return req.Do(api) +} + +type AddStickerToSetP struct { + UserID int `json:"user_id"` + Name string `json:"name"` + Sticker InputSticker `json:"sticker"` +} + +func (api *Api) AddStickerToSet(p AddStickerToSetP) (bool, error) { + req := NewRequest[bool]("addStickerToSet", p) + return req.Do(api) +} + +type SetStickerPositionInSetP struct { + Sticker string `json:"sticker"` + Position int `json:"position"` +} + +func (api *Api) SetStickerPosition(p SetStickerPositionInSetP) (bool, error) { + req := NewRequest[bool]("setStickerPosition", p) + return req.Do(api) +} + +type DeleteStickerFromSetP struct { + Sticker string `json:"sticker"` +} + +func (api *Api) DeleteStickerFromSet(p DeleteStickerFromSetP) (bool, error) { + req := NewRequest[bool]("deleteStickerFromSet", p) + return req.Do(api) +} + +type ReplaceStickerInSetP struct { + UserID int `json:"user_id"` + Name string `json:"name"` + OldSticker string `json:"old_sticker"` + Sticker InputSticker `json:"sticker"` +} + +func (api *Api) ReplaceStickerInSet(p ReplaceStickerInSetP) (bool, error) { + req := NewRequest[bool]("replaceStickerInSet", p) + return req.Do(api) +} + +type SetStickerEmojiListP struct { + Sticker string `json:"sticker"` + EmojiList []string `json:"emoji_list"` +} + +func (api *Api) SetStickerEmojiList(p SetStickerEmojiListP) (bool, error) { + req := NewRequest[bool]("setStickerEmojiList", p) + return req.Do(api) +} + +type SetStickerKeywordsP struct { + Sticker string `json:"sticker"` + Keywords []string `json:"keywords"` +} + +func (api *Api) SetStickerKeywords(p SetStickerKeywordsP) (bool, error) { + req := NewRequest[bool]("setStickerKeywords", p) + return req.Do(api) +} + +type SetStickerMaskPositionP struct { + Sticker string `json:"sticker"` + MaskPosition *MaskPosition `json:"mask_position,omitempty"` +} + +func (api *Api) SetStickerMaskPosition(p SetStickerMaskPositionP) (bool, error) { + req := NewRequest[bool]("setStickerMaskPosition", p) + return req.Do(api) +} + +type SetStickerSetTitleP struct { + Name string `json:"name"` + Title string `json:"title"` +} + +func (api *Api) SetStickerSetTitle(p SetStickerSetTitleP) (bool, error) { + req := NewRequest[bool]("setStickerSetTitle", p) + return req.Do(api) +} + +type SetStickerSetThumbnailP struct { + Name string `json:"name"` + UserID int `json:"user_id"` + Thumbnail string `json:"thumbnail"` + Format InputStickerFormat `json:"format"` +} + +func (api *Api) SetStickerSetThumbnail(p SetStickerSetThumbnailP) (bool, error) { + req := NewRequest[bool]("setStickerSetThumbnail", p) + return req.Do(api) +} + +type SetCustomEmojiStickerSetThumbnailP struct { + Name string `json:"name"` + CustomEmojiID string `json:"custom_emoji_id,omitempty"` +} + +func (api *Api) SetCustomEmojiStickerSetThumbnail(p SetStickerSetThumbnailP) (bool, error) { + req := NewRequest[bool]("setCustomEmojiStickerSetThumbnail", p) + return req.Do(api) +} + +type DeleteStickerSetP struct { + Name string `json:"name"` +} + +func (api *Api) DeleteStickerSet(p DeleteStickerSetP) (bool, error) { + req := NewRequest[bool]("deleteStickerSet", p) + return req.Do(api) +} diff --git a/stickers.go b/tgapi/stickers_types.go similarity index 58% rename from stickers.go rename to tgapi/stickers_types.go index a7f33fe..299c492 100644 --- a/stickers.go +++ b/tgapi/stickers_types.go @@ -1,4 +1,4 @@ -package laniakea +package tgapi type MaskPositionPoint string @@ -34,12 +34,12 @@ type Sticker struct { IsVideo bool `json:"is_video"` Thumbnail *PhotoSize `json:"thumbnail,omitempty"` - Emoji string `json:"emoji,omitempty"` - SetName string `json:"set_name,omitempty"` + Emoji *string `json:"emoji,omitempty"` + SetName *string `json:"set_name,omitempty"` MaskPosition *MaskPosition `json:"mask_position,omitempty"` - CustomEmojiID string `json:"custom_emoji_id,omitempty"` - NeedRepainting bool `json:"need_repainting,omitempty"` - FileSize int `json:"file_size,omitempty"` + CustomEmojiID *string `json:"custom_emoji_id,omitempty"` + NeedRepainting *bool `json:"need_repainting,omitempty"` + FileSize *int `json:"file_size,omitempty"` } type StickerSet struct { Name string `json:"name"` @@ -63,31 +63,3 @@ type InputSticker struct { MaskPosition *MaskPosition `json:"mask_position,omitempty"` Keywords []string `json:"keywords,omitempty"` } - -type SendStickerP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - - Sticker string `json:"sticker"` - Emoji string `json:"emoji,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` -} - -func (api *Api) SendSticker(p SendStickerP) (*Message, error) { - req := NewRequest[Message]("sendSticker", p) - return req.Do(api) -} - -type GetStickerSetP struct { - Name string `json:"name"` -} - -func (api *Api) GetStickerSet(p GetStickerSetP) (*StickerSet, error) { - req := NewRequest[StickerSet]("getStickerSet", p) - return req.Do(api) -} diff --git a/tgapi/types.go b/tgapi/types.go new file mode 100644 index 0000000..33b25ba --- /dev/null +++ b/tgapi/types.go @@ -0,0 +1,113 @@ +package tgapi + +type Update struct { + UpdateID int `json:"update_id"` + Message *Message `json:"message"` + EditedMessage *Message `json:"edited_message,omitempty"` + ChannelPost *Message `json:"channel_post,omitempty"` + EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + BusinessConnection *BusinessConnection `json:"business_connection,omitempty"` + BusinessMessage *Message `json:"business_message,omitempty"` + EditedBusinessMessage *Message `json:"edited_business_message,omitempty"` + DeletedBusinessMessage *Message `json:"deleted_business_messages,omitempty"` + MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"` + MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"` + CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` + InlineQuery int + ChosenInlineResult int +} + +type File struct { + FileId string `json:"file_id"` + FileUniqueID string `json:"file_unique_id"` + FileSize int `json:"file_size,omitempty"` + FilePath string `json:"file_path,omitempty"` +} + +type Audio struct { + FileID string `json:"file_id"` + FileUniqueID string `json:"file_unique_id"` + Duration int `json:"duration"` + + Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` + FileName string `json:"file_name,omitempty"` + MimeType string `json:"mime_type,omitempty"` + FileSize int `json:"file_size,omitempty"` + Thumbnail *PhotoSize `json:"thumbnail,omitempty"` +} + +type Location struct { + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + HorizontalAccuracy float64 `json:"horizontal_accuracy"` + LivePeriod int `json:"live_period"` + Heading int `json:"heading"` + ProximityAlertRadius int `json:"proximity_alert_radius"` +} +type Venue struct { + Location Location `json:"location"` + Title string `json:"title"` + Address string `json:"address"` + FoursquareID string `json:"foursquare_id,omitempty"` + FoursquareType string `json:"foursquare_type,omitempty"` + GooglePlaceID string `json:"google_place_id,omitempty"` + GooglePlaceType string `json:"google_place_type,omitempty"` +} + +type WebAppInfo struct { + URL string `json:"url"` +} + +type StarAmount struct { + Amount int `json:"amount"` + NanostarAmount int `json:"nanostar_amount"` +} + +// Gifts + +type AcceptedGiftTypes struct { + UnlimitedGifts bool `json:"unlimited_gifts"` + LimitedGifts bool `json:"limited_gifts"` + UniqueGifts bool `json:"unique_gifts"` + PremiumSubscription bool `json:"premium_subscription"` + GiftsFromChannels bool `json:"gifts_from_channels"` +} + +type UniqueGiftColors struct { + ModelCustomEmojiID string `json:"model_custom_emoji_id"` + SymbolCustomEmojiID string `json:"symbol_custom_emoji_id"` + LightThemeMainColor int `json:"light_theme_main_color"` + LightThemeOtherColors []int `json:"light_theme_other_colors"` + DarkThemeMainColor int `json:"dark_theme_main_color"` + DarkThemeOtherColors []int `json:"dark_theme_other_colors"` +} + +type GiftBackground struct { + CenterColor int `json:"center_color"` + EdgeColor int `json:"edge_color"` + TextColor int `json:"text_color"` +} +type Gift struct { + ID string `json:"id"` + Sticker Sticker `json:"sticker"` + StarCount int `json:"star_count"` + UpdateStarCount *int `json:"update_star_count,omitempty"` + IsPremium *bool `json:"is_premium,omitempty"` + HasColors *bool `json:"has_colors,omitempty"` + TotalCount *int `json:"total_count,omitempty"` + RemainingCount *int `json:"remaining_count,omitempty"` + PersonalTotalCount *int `json:"personal_total_count,omitempty"` + PersonalRemainingCount *int `json:"personal_remaining_count,omitempty"` + Background GiftBackground `json:"background,omitempty"` + UniqueGiftVariantColor *int `json:"unique_gift_variant_color,omitempty"` + PublisherChat *Chat `json:"publisher_chat,omitempty"` +} +type Gifts struct { + Gifts []Gift `json:"gifts"` +} + +type OwnedGiftType string +type BaseOwnedGift struct { + Type OwnedGiftType `json:"type"` +} diff --git a/uploader.go b/tgapi/uploader.go similarity index 70% rename from uploader.go rename to tgapi/uploader.go index 8e76341..33b9b52 100644 --- a/uploader.go +++ b/tgapi/uploader.go @@ -1,4 +1,4 @@ -package laniakea +package tgapi import ( "bytes" @@ -9,6 +9,7 @@ import ( "net/http" "path/filepath" + "git.nix13.pw/scuroneko/laniakea/utils" "git.nix13.pw/scuroneko/slog" ) @@ -80,7 +81,7 @@ func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) { w.Close() return nil, err } - err = Encode(w, u.params) + err = utils.Encode(w, u.params) if err != nil { w.Close() return nil, err @@ -122,11 +123,31 @@ func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) { return response.Result, nil } -func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) { +type UploadPhotoP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Caption string `json:"caption,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadPhoto(file UploaderFile, params UploadPhotoP) (*Message, error) { req := NewUploaderRequest[Message]("sendPhoto", file, params) return req.Do(u) } +// setChatPhoto https://core.telegram.org/bots/api#setchatphoto +type UploadChatPhotoP struct { +} + func uploaderTypeByExt(filename string) UploaderFileType { ext := filepath.Ext(filename) switch ext { diff --git a/tgapi/users_methods.go b/tgapi/users_methods.go new file mode 100644 index 0000000..d54d496 --- /dev/null +++ b/tgapi/users_methods.go @@ -0,0 +1,34 @@ +package tgapi + +type GetUserProfilePhotosP struct { + UserID int `json:"user_id"` + Offset int `json:"offset,omitempty"` + Limit int `json:"limit,omitempty"` +} + +func (api *Api) GetUserProfilePhotos(p GetUserProfilePhotosP) (UserProfilePhotos, error) { + req := NewRequest[UserProfilePhotos]("getUserProfilePhotos", p) + return req.Do(api) +} + +type GetUserProfileAudiosP struct { + UserID int `json:"user_id"` + Offset int `json:"offset,omitempty"` + Limit int `json:"limit,omitempty"` +} + +func (api *Api) GetUserProfileAudios(p GetUserProfileAudiosP) (UserProfileAudios, error) { + req := NewRequest[UserProfileAudios]("getUserProfileAudios", p) + return req.Do(api) +} + +type SetUserEmojiStatusP struct { + UserID int `json:"user_id"` + EmojiID string `json:"emoji_status_custom_emoji_id,omitempty"` + ExpirationDate int `json:"emoji_status_expiration_date,omitempty"` +} + +func (api *Api) SetUserEmojiStatus(p SetUserEmojiStatusP) (bool, error) { + req := NewRequest[bool]("setUserEmojiStatus", p) + return req.Do(api) +} diff --git a/tgapi/users_types.go b/tgapi/users_types.go new file mode 100644 index 0000000..9c674c1 --- /dev/null +++ b/tgapi/users_types.go @@ -0,0 +1,40 @@ +package tgapi + +type User struct { + ID int `json:"id"` + IsBot bool `json:"is_bot"` + FirstName string `json:"first_name"` + LastName string `json:"last_name,omitempty"` + Username string `json:"username,omitempty"` + LanguageCode string `json:"language_code,omitempty"` + IsPremium bool `json:"is_premium,omitempty"` + AddedToAttachmentMenu bool `json:"added_to_attachment_menu,omitempty"` + CanJoinGroups bool `json:"can_join_groups,omitempty"` + CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"` + SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"` + CanConnectToBusiness bool `json:"can_connect_to_business,omitempty"` + HasMainWebApp bool `json:"has_main_web_app,omitempty"` + HasTopicsEnabled bool `json:"has_topics_enabled,omitempty"` + AllowsUsersToCreateTopics bool `json:"allows_users_to_create_topics,omitempty"` +} + +type UserProfilePhotos struct { + TotalCount int `json:"total_count"` + Photos [][]PhotoSize `json:"photos"` +} +type UserProfileAudios struct { + TotalCount int `json:"total_count"` + Audios []Audio `json:"audios"` +} + +type UserRating struct { + Level int `json:"level"` + Rating int `json:"rating"` + CurrentLevelRating int `json:"current_level_rating"` + NextLevelRating int `json:"next_level_rating"` +} +type Birthdate struct { + Day int `json:"day"` + Month int `json:"month"` + Year int `json:"year"` +} diff --git a/tgapi/utils.go b/tgapi/utils.go new file mode 100644 index 0000000..a982ea3 --- /dev/null +++ b/tgapi/utils.go @@ -0,0 +1,15 @@ +package tgapi + +import ( + "os" + + "git.nix13.pw/scuroneko/slog" +) + +func GetLoggerLevel() slog.LogLevel { + level := slog.FATAL + if os.Getenv("DEBUG") == "true" { + level = slog.DEBUG + } + return level +} diff --git a/utils.go b/utils.go index 5b0f372..7dcedde 100644 --- a/utils.go +++ b/utils.go @@ -1,86 +1,10 @@ package laniakea -import ( - "encoding/json" - "fmt" - "os" - "strings" +func Ptr[T any](v T) *T { return &v } - "git.nix13.pw/scuroneko/slog" -) - -func GetLoggerLevel() slog.LogLevel { - level := slog.FATAL - if os.Getenv("DEBUG") == "true" { - level = slog.DEBUG +func Val[T any](p *T, def T) T { + if p != nil { + return *p } - return level -} - -// MapToStruct unsafe function -func MapToStruct(m map[string]any, s any) error { - data, err := json.Marshal(m) - if err != nil { - return err - } - err = json.Unmarshal(data, s) - return err -} - -// SliceToStruct unsafe function -func SliceToStruct(sl []any, s any) error { - data, err := json.Marshal(sl) - if err != nil { - return err - } - err = json.Unmarshal(data, s) - return err -} - -// AnyToStruct unsafe function -func AnyToStruct(src, dest any) error { - data, err := json.Marshal(src) - if err != nil { - return err - } - err = json.Unmarshal(data, dest) - return err -} - -func MapToJson(m map[string]any) (string, error) { - data, err := json.Marshal(m) - return string(data), err -} - -func StructToMap(s any) (map[string]any, error) { - data, err := json.Marshal(s) - if err != nil { - return nil, err - } - m := make(map[string]any) - err = json.Unmarshal(data, &m) - return m, err -} - -func Map[T, V any](ts []T, fn func(T) V) []V { - result := make([]V, len(ts)) - for i, t := range ts { - result[i] = fn(t) - } - return result -} - -func EscapeMarkdown(s string) string { - s = strings.ReplaceAll(s, "_", `\_`) - s = strings.ReplaceAll(s, "*", `\*`) - s = strings.ReplaceAll(s, "[", `\[`) - return strings.ReplaceAll(s, "`", "\\`") -} - -func EscapeMarkdownV2(s string) string { - symbols := []string{"_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"} - for _, symbol := range symbols { - s = strings.ReplaceAll(s, symbol, fmt.Sprintf("\\%s", symbol)) - } - return s + return def } diff --git a/multipart.go b/utils/multipart.go similarity index 99% rename from multipart.go rename to utils/multipart.go index 5fc75df..89d2fc7 100644 --- a/multipart.go +++ b/utils/multipart.go @@ -1,4 +1,4 @@ -package laniakea +package utils import ( "encoding/json" diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..c782c58 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,100 @@ +package utils + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "git.nix13.pw/scuroneko/slog" +) + +func GetLoggerLevel() slog.LogLevel { + level := slog.FATAL + if os.Getenv("DEBUG") == "true" { + level = slog.DEBUG + } + return level +} + +func Cast[A, B any](src A) (*B, error) { + m, err := StructToMap(src) + if err != nil { + return nil, err + } + + out := new(B) + err = MapToStruct(m, out) + if err != nil { + return nil, err + } + return out, nil +} + +// MapToStruct unsafe function +func MapToStruct(m map[string]any, s any) error { + data, err := json.Marshal(m) + if err != nil { + return err + } + err = json.Unmarshal(data, s) + return err +} + +// SliceToStruct unsafe function +func SliceToStruct(sl []any, s any) error { + data, err := json.Marshal(sl) + if err != nil { + return err + } + err = json.Unmarshal(data, s) + return err +} + +// AnyToStruct unsafe function +func AnyToStruct(src, dest any) error { + data, err := json.Marshal(src) + if err != nil { + return err + } + err = json.Unmarshal(data, dest) + return err +} + +func MapToJson(m map[string]any) (string, error) { + data, err := json.Marshal(m) + return string(data), err +} + +func StructToMap(s any) (map[string]any, error) { + data, err := json.Marshal(s) + if err != nil { + return nil, err + } + m := make(map[string]any) + err = json.Unmarshal(data, &m) + return m, err +} + +func Map[T, V any](ts []T, fn func(T) V) []V { + result := make([]V, len(ts)) + for i, t := range ts { + result[i] = fn(t) + } + return result +} + +func EscapeMarkdown(s string) string { + s = strings.ReplaceAll(s, "_", `\_`) + s = strings.ReplaceAll(s, "*", `\*`) + s = strings.ReplaceAll(s, "[", `\[`) + return strings.ReplaceAll(s, "`", "\\`") +} + +func EscapeMarkdownV2(s string) string { + symbols := []string{"_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"} + for _, symbol := range symbols { + s = strings.ReplaceAll(s, symbol, fmt.Sprintf("\\%s", symbol)) + } + return s +} diff --git a/utils/version.go b/utils/version.go new file mode 100644 index 0000000..adc8290 --- /dev/null +++ b/utils/version.go @@ -0,0 +1,8 @@ +package utils + +const ( + VersionString = "0.5.0" + VersionMajor = 0 + VersionMinor = 5 + VersionPatch = 0 +) diff --git a/version.go b/version.go deleted file mode 100644 index 2b17a5f..0000000 --- a/version.go +++ /dev/null @@ -1,8 +0,0 @@ -package laniakea - -const ( - VersionString = "0.4.4-1" - VersionMajor = 0 - VersionMinor = 4 - VersionPatch = 4 -) -- 2.53.0 From 2a030aa0d82bea9cce3e1c4874e8dd66df256e21 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 11 Feb 2026 17:43:36 +0300 Subject: [PATCH 10/16] WIP v0.5.0 --- tgapi/business_methods.go | 16 ++++++++++++++++ tgapi/types.go | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tgapi/business_methods.go b/tgapi/business_methods.go index 2c9ee47..aed183e 100644 --- a/tgapi/business_methods.go +++ b/tgapi/business_methods.go @@ -146,4 +146,20 @@ func (api *Api) TransferBusinessAccountStart(p TransferBusinessAccountStartP) (b } type GetBusinessAccountGiftsP struct { + BusinessConnectionID string `json:"business_connection_id"` + ExcludeUnsaved bool `json:"exclude_unsaved,omitempty"` + ExcludeSaved bool `json:"exclude_saved,omitempty"` + ExcludeUnlimited bool `json:"exclude_unlimited,omitempty"` + ExcludeLimitedUpgradable bool `json:"exclude_limited_upgradable,omitempty"` + ExcludeLimitedNonUpgradable bool `json:"exclude_limited_non_upgradable,omitempty"` + ExcludeUnique bool `json:"exclude_unique,omitempty"` + ExcludeFromBlockchain bool `json:"exclude_from_blockchain,omitempty"` + SortByPrice bool `json:"sort_by_price,omitempty"` + Offset string `json:"offset,omitempty"` + Limit int `json:"limit,omitempty"` +} + +func (api *Api) GetBusinessAccountGifts(p GetBusinessAccountGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getBusinessAccountGifts", p) + return req.Do(api) } diff --git a/tgapi/types.go b/tgapi/types.go index 33b25ba..2f4fd17 100644 --- a/tgapi/types.go +++ b/tgapi/types.go @@ -109,5 +109,36 @@ type Gifts struct { type OwnedGiftType string type BaseOwnedGift struct { - Type OwnedGiftType `json:"type"` + Type OwnedGiftType `json:"type"` + OwnerGiftID *string `json:"owner_gift_id,omitempty"` + SendDate *int `json:"send_date,omitempty"` + IsSaved *bool `json:"is_saved,omitempty"` +} +type OwnedGiftRegular struct { + BaseOwnedGift + Gift Gift `json:"gift"` + SenderUser User `json:"sender_user,omitempty"` + Text string `json:"text,omitempty"` + Entities []MessageEntity `json:"entities,omitempty"` + IsPrivate *bool `json:"is_private,omitempty"` + CanBeUpgraded *bool `json:"can_be_upgraded,omitempty"` + WasRefunded *bool `json:"was_refunded,omitempty"` + ConvertStarCount *int `json:"convert_star_count,omitempty"` + PrepaidUpgradeStarCount *int `json:"prepaid_upgrade_star_count,omitempty"` + IsUpgradeSeparate *bool `json:"is_upgrade_separate,omitempty"` + UniqueGiftNumber *int `json:"unique_gift_number,omitempty"` +} +type OwnedGiftUnique struct { + BaseOwnedGift + CanBeTransferred *bool `json:"can_be_transferred,omitempty"` + TransferStarCount *int `json:"transfer_star_count,omitempty"` + NextTransferDate *int `json:"next_transfer_date,omitempty"` +} +type OwnedGifts struct { + TotalCount int `json:"total_count"` + Gifts []struct { + OwnedGiftRegular + OwnedGiftUnique + } `json:"gifts"` + NextOffset string `json:"next_offset"` } -- 2.53.0 From c4b827fb31eb4fc61e23b785de230697b4094de1 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 11 Feb 2026 17:44:51 +0300 Subject: [PATCH 11/16] WIP v0.5.0 --- tgapi/types.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tgapi/types.go b/tgapi/types.go index 2f4fd17..e400341 100644 --- a/tgapi/types.go +++ b/tgapi/types.go @@ -107,6 +107,11 @@ type Gifts struct { Gifts []Gift `json:"gifts"` } +const ( + OwnedGiftRegularType OwnedGiftType = "regular" + OwnedGiftUniqueType OwnedGiftType = "unique" +) + type OwnedGiftType string type BaseOwnedGift struct { Type OwnedGiftType `json:"type"` -- 2.53.0 From f2e600e0a9caabbdd5f26a6429c25b0831acd4cd Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 11 Feb 2026 20:02:13 +0300 Subject: [PATCH 12/16] WIP v0.5.0 --- go.mod | 9 +-- go.sum | 10 ++++ tgapi/attachments_methods.go | 108 +++++++++++++++------------------- tgapi/attachments_types.go | 90 +++++++--------------------- tgapi/bot_methods.go | 40 +++++-------- tgapi/bot_types.go | 61 ++++--------------- tgapi/business_methods.go | 111 ++++++++++++++++++++++++++++++++--- tgapi/business_types.go | 60 +++++++++++++++++++ tgapi/chat_methods.go | 59 ++++++++++++------- tgapi/chat_types.go | 94 ++++++++++++----------------- tgapi/messages_methods.go | 50 +++++++--------- tgapi/messages_types.go | 27 +++------ tgapi/types.go | 92 ++++++++++++++++++++++++++--- tgapi/users_methods.go | 17 ++++++ tgapi/users_types.go | 30 +++++----- 15 files changed, 490 insertions(+), 368 deletions(-) diff --git a/go.mod b/go.mod index 47a6504..40bdc50 100644 --- a/go.mod +++ b/go.mod @@ -17,13 +17,14 @@ require ( github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/muir/sqltoken v0.2.1 // indirect + github.com/muir/list v1.2.1 // indirect + github.com/muir/sqltoken v0.3.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.48.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect ) diff --git a/go.sum b/go.sum index 24e8718..a552309 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,12 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/muir/list v1.2.1 h1:lmF8fz2B1WbXkzHr/Eh0oWPJArDBzWqIifOwbA4gWSo= +github.com/muir/list v1.2.1/go.mod h1:v0l2f997MxCohQlD7PTejJqyYKwFVz/i3mTpDl4LAf0= github.com/muir/sqltoken v0.2.1 h1:19KvJrCj9aOMfU921hjnizWPlQmPTe+tb36zupOY2FA= github.com/muir/sqltoken v0.2.1/go.mod h1:sSlj5M0VqQ4OuedmxwWs1TmzzRXaH3DLf5ukzg6meIo= +github.com/muir/sqltoken v0.3.0 h1:3xbcqr80f3IA4OlwkOpdIHC4DTu6gsi1TwMqgYL4Dpg= +github.com/muir/sqltoken v0.3.0/go.mod h1:+OSmbGI22QcVZ6DCzlHT8EAzEq/mqtqedtPP91Le+3A= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4= @@ -55,6 +59,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -71,6 +77,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -79,6 +87,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/tgapi/attachments_methods.go b/tgapi/attachments_methods.go index 4dc7c3d..9241a68 100644 --- a/tgapi/attachments_methods.go +++ b/tgapi/attachments_methods.go @@ -6,10 +6,10 @@ type SendPhotoP struct { MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - Photo string `json:"photo"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + Photo string `json:"photo"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` HasSpoiler bool `json:"has_spoiler,omitempty"` @@ -34,13 +34,13 @@ type SendAudioP struct { MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - Audio string `json:"audio"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - Duration int `json:"duration,omitempty"` - Performer string `json:"performer,omitempty"` - Title string `json:"title,omitempty"` + Audio string `json:"audio"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` DisableNotification bool `json:"disable_notification,omitempty"` ProtectContent bool `json:"protect_content,omitempty"` @@ -63,10 +63,10 @@ type SendDocumentP struct { MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - Document string `json:"document"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + Document string `json:"document"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` DisableNotification bool `json:"disable_notification,omitempty"` ProtectContent bool `json:"protect_content,omitempty"` @@ -93,12 +93,12 @@ type SendVideoP struct { Duration int `json:"duration,omitempty"` Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` - Cover string `json:"cover,omitempty"` + Cover int `json:"cover,omitempty"` - StartTimestamp int `json:"start_timestamp,omitempty"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + StartTimestamp int `json:"start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` HasSpoiler bool `json:"has_spoiler,omitempty"` @@ -129,15 +129,15 @@ type SendAnimationP struct { Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` @@ -155,15 +155,15 @@ type SendVoiceP struct { MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - Voice string `json:"voice"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - Duration int `json:"duration,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` + Voice string `json:"voice"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` @@ -199,18 +199,18 @@ func (api *Api) SendVideoNote(params SendVideoNoteP) (Message, error) { return req.Do(api) } -type SendPaidMediaP[T InputPaidMedia] struct { +type SendPaidMediaP struct { BusinessConnectionID string `json:"business_connection_id,omitempty"` ChatID int `json:"chat_id"` MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` StarCount int `json:"star_count,omitempty"` - Media []T `json:"media"` + Media []InputPaidMedia `json:"media"` Payload string `json:"payload,omitempty"` Caption string `json:"caption,omitempty"` ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` DisableNotification bool `json:"disable_notification,omitempty"` ProtectContent bool `json:"protect_content,omitempty"` @@ -221,22 +221,18 @@ type SendPaidMediaP[T InputPaidMedia] struct { ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` } -func (api *Api) SendPaidMediaPhoto(params SendPaidMediaP[InputPaidMediaPhoto]) (Message, error) { - req := NewRequest[Message]("sendPaidMedia", params) - return req.Do(api) -} -func (api *Api) SendPaidMediaVideo(params SendPaidMediaP[InputPaidMediaVideo]) (Message, error) { +func (api *Api) SendPaidMedia(params SendPaidMediaP) (Message, error) { req := NewRequest[Message]("sendPaidMedia", params) return req.Do(api) } -type SendMediaGroupP[T InputMedia] struct { +type SendMediaGroupP struct { BusinessConnectionID string `json:"business_connection_id,omitempty"` ChatID int `json:"chat_id"` MessageThreadID int `json:"message_thread_id,omitempty"` DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` - Media []T `json:"media"` + Media []InputMedia `json:"media"` DisableNotification bool `json:"disable_notification,omitempty"` ProtectContent bool `json:"protect_content,omitempty"` AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` @@ -244,19 +240,7 @@ type SendMediaGroupP[T InputMedia] struct { ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` } -func (api *Api) SendMediaGroupAudio(p SendMediaGroupP[InputMediaAudio]) (Message, error) { - req := NewRequest[Message]("sendMediaGroupAudio", p) - return req.Do(api) -} -func (api *Api) SendMediaGroupDocument(p SendMediaGroupP[InputMediaDocument]) (Message, error) { - req := NewRequest[Message]("sendMediaGroupDocument", p) - return req.Do(api) -} -func (api *Api) SendMediaGroupPhoto(p SendMediaGroupP[InputMediaPhoto]) (Message, error) { - req := NewRequest[Message]("sendMediaGroupPhoto", p) - return req.Do(api) -} -func (api *Api) SendMediaGroupVideo(p SendMediaGroupP[InputMediaVideo]) (Message, error) { - req := NewRequest[Message]("sendMediaGroupVideo", p) +func (api *Api) SendMediaGroup(p SendMediaGroupP) (Message, error) { + req := NewRequest[Message]("sendMediaGroup", p) return req.Do(api) } diff --git a/tgapi/attachments_types.go b/tgapi/attachments_types.go index 2fa8072..89dc0ef 100644 --- a/tgapi/attachments_types.go +++ b/tgapi/attachments_types.go @@ -1,7 +1,24 @@ package tgapi -type InputMedia interface { - InputMediaPhoto | InputMediaVideo | InputMediaAudio | InputMediaDocument +type InputMedia struct { + Type InputMediaType `json:"type"` + Media string `json:"media"` + + Caption *string `json:"caption,omitempty"` + ParseMode *ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` + HasSpoiler *bool `json:"has_spoiler,omitempty"` + + Cover *string `json:"cover"` + StartTimestamp *int `json:"start_timestamp"` + Width *int `json:"width,omitempty"` + Height *int `json:"height,omitempty"` + Duration *int `json:"duration,omitempty"` + SupportsStreaming *bool `json:"supports_streaming,omitempty"` + + Performer *string `json:"performer,omitempty"` + Title *string `json:"title,omitempty"` } type InputMediaType string @@ -14,66 +31,6 @@ const ( InputMediaTypeAudio InputMediaType = "audio" ) -type InputMediaPhoto struct { - Type InputMediaType `json:"type"` - Media string `json:"media"` - - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` -} -type InputMediaVideo struct { - Type InputMediaType `json:"type"` - Media string `json:"media"` - - Cover string `json:"cover"` - StartTimestamp int `json:"start_timestamp"` - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - Duration int `json:"duration,omitempty"` - SupportsStreaming bool `json:"supports_streaming,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` -} -type InputMediaAnimation struct { - Type InputMediaType `json:"type"` - Media string `json:"media"` - - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - Duration int `json:"duration,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` -} -type InputMediaAudio struct { - Type InputMediaType `json:"type"` - Media string `json:"media"` - - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - Duration int `json:"duration,omitempty"` - Performer string `json:"performer,omitempty"` - Title string `json:"title,omitempty"` -} -type InputMediaDocument struct { - Type InputMediaType `json:"type"` - Media string `json:"media"` - - Caption string `json:"caption,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` -} - type InputPaidMediaType string const ( @@ -81,14 +38,7 @@ const ( InputPaidMediaTypePhoto InputPaidMediaType = "photo" ) -type InputPaidMedia interface { - InputPaidMediaVideo | InputPaidMediaPhoto -} -type InputPaidMediaPhoto struct { - Type InputPaidMediaType `json:"type"` - Media string `json:"media"` -} -type InputPaidMediaVideo struct { +type InputPaidMedia struct { Type InputPaidMediaType `json:"type"` Media string `json:"media"` diff --git a/tgapi/bot_methods.go b/tgapi/bot_methods.go index cdc887b..97e72b8 100644 --- a/tgapi/bot_methods.go +++ b/tgapi/bot_methods.go @@ -1,9 +1,9 @@ package tgapi type SetMyCommandsP struct { - Commands []BotCommand `json:"commands"` - Scope *BaseBotCommandScope `json:"scope,omitempty"` - Language string `json:"language_code,omitempty"` + Commands []BotCommand `json:"commands"` + Scope *BotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` } func (api *Api) SetMyCommands(p SetMyCommandsP) (bool, error) { @@ -12,8 +12,8 @@ func (api *Api) SetMyCommands(p SetMyCommandsP) (bool, error) { } type DeleteMyCommandsP struct { - Scope *BaseBotCommandScope `json:"scope,omitempty"` - Language string `json:"language_code,omitempty"` + Scope *BotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` } func (api *Api) DeleteMyCommands(p DeleteMyCommandsP) (bool, error) { @@ -22,8 +22,8 @@ func (api *Api) DeleteMyCommands(p DeleteMyCommandsP) (bool, error) { } type GetMyCommands struct { - Scope *BaseBotCommandScope `json:"scope,omitempty"` - Language string `json:"language_code,omitempty"` + Scope *BotCommandScope `json:"scope,omitempty"` + Language string `json:"language_code,omitempty"` } func (api *Api) GetMyCommands(p GetMyCommands) ([]BotCommand, error) { @@ -88,15 +88,11 @@ func (api *Api) GetMyShortDescription(p GetMyShortDescription) (BotShortDescript return req.Do(api) } -type SetMyProfilePhotoP[T InputProfilePhoto] struct { - Photo T `json:"photo"` +type SetMyProfilePhotoP struct { + Photo InputProfilePhoto `json:"photo"` } -func (api *Api) SetMyProfilePhotoStatic(p SetMyProfilePhotoP[InputProfilePhotoStatic]) (bool, error) { - req := NewRequest[bool]("setMyProfilePhoto", p) - return req.Do(api) -} -func (api *Api) SetMyProfilePhotoAnimated(p SetMyProfilePhotoP[InputProfilePhotoAnimated]) (bool, error) { +func (api *Api) SetMyProfilePhoto(p SetMyProfilePhotoP) (bool, error) { req := NewRequest[bool]("setMyProfilePhoto", p) return req.Do(api) } @@ -105,20 +101,12 @@ func (api *Api) RemoveMyProfilePhoto() (bool, error) { return req.Do(api) } -type SetChatMenuButtonP[T MenuButton] struct { - ChatID int `json:"chat_id"` - MenuButton T `json:"menu_button"` +type SetChatMenuButtonP struct { + ChatID int `json:"chat_id"` + MenuButton MenuButtonType `json:"menu_button"` } -func (api *Api) SetChatMenuButtonCommands(p SetChatMenuButtonP[MenuButtonCommands]) (bool, error) { - req := NewRequest[bool]("setChatMenuButton", p) - return req.Do(api) -} -func (api *Api) SetChatMenuButtonWebApp(p SetChatMenuButtonP[MenuButtonWebApp]) (bool, error) { - req := NewRequest[bool]("setChatMenuButton", p) - return req.Do(api) -} -func (api *Api) SetChatMenuButtonDefault(p SetChatMenuButtonP[MenuButtonDefault]) (bool, error) { +func (api *Api) SetChatMenuButton(p SetChatMenuButtonP) (bool, error) { req := NewRequest[bool]("setChatMenuButton", p) return req.Do(api) } diff --git a/tgapi/bot_types.go b/tgapi/bot_types.go index 512bbdf..d73c30c 100644 --- a/tgapi/bot_types.go +++ b/tgapi/bot_types.go @@ -16,33 +16,10 @@ const ( BotCommandScopeChatMemberType BotCommandScopeType = "chat_member" ) -type BaseBotCommandScope struct { - Type BotCommandScopeType `json:"type"` -} -type BotCommandScopeDefault struct { - BaseBotCommandScope -} -type BotCommandScopePrivateChats struct { - BaseBotCommandScope -} -type BotCommandScopeAllGroupChats struct { - BaseBotCommandScope -} -type BotCommandScopeAllChatAdministrators struct { - BaseBotCommandScope -} -type BotCommandScopeChat struct { - BaseBotCommandScope - ChatID int `json:"chat_id"` -} -type BotCommandScopeChatAdministrators struct { - BaseBotCommandScope - ChatID int `json:"chat_id"` -} -type BotCommandScopeChatMember struct { - BaseBotCommandScope - ChatID int `json:"chat_id"` - UserID int `json:"user_id"` +type BotCommandScope struct { + Type BotCommandScopeType `json:"type"` + ChatID *int `json:"chat_id,omitempty"` + UserID *int `json:"user_id,omitempty"` } type BotName struct { @@ -61,20 +38,15 @@ const ( ) type InputProfilePhotoType string -type InputProfilePhoto interface { - InputProfilePhotoStatic | InputProfilePhotoAnimated -} -type BaseInputProfilePhoto struct { +type InputProfilePhoto struct { Type InputProfilePhotoType `json:"type"` -} -type InputProfilePhotoStatic struct { - BaseInputProfilePhoto - Photo string `json:"photo"` -} -type InputProfilePhotoAnimated struct { - BaseInputProfilePhoto - Animation string `json:"animation"` - MainFrameTimestamp float64 `json:"main_frame_timestamp"` + + // Static + Photo *string `json:"photo,omitempty"` + + // Animated + Animation *string `json:"animation,omitempty"` + MainFrameTimestamp *float64 `json:"main_frame_timestamp,omitempty"` } const ( @@ -84,16 +56,9 @@ const ( ) type MenuButtonType string -type MenuButton interface { - MenuButtonCommands | MenuButtonDefault | MenuButtonWebApp -} type BaseMenuButton struct { Type MenuButtonType `json:"type"` -} -type MenuButtonCommands struct{ BaseMenuButton } -type MenuButtonDefault struct{ BaseMenuButton } -type MenuButtonWebApp struct { - BaseMenuButton + // WebApp Text string `json:"text"` WebApp WebAppInfo `json:"web_app"` } diff --git a/tgapi/business_methods.go b/tgapi/business_methods.go index aed183e..fcc4660 100644 --- a/tgapi/business_methods.go +++ b/tgapi/business_methods.go @@ -90,17 +90,13 @@ func (api *Api) SetBusinessAccountBio(p SetBusinessAccountBioP) (bool, error) { return req.Do(api) } -type SetBusinessAccountProfilePhoto[T InputProfilePhoto] struct { - BusinessConnectionID string `json:"business_connection_id"` - Photo T `json:"photo,omitempty"` - IsPublic bool `json:"is_public,omitempty"` +type SetBusinessAccountProfilePhoto struct { + BusinessConnectionID string `json:"business_connection_id"` + Photo InputProfilePhoto `json:"photo,omitempty"` + IsPublic bool `json:"is_public,omitempty"` } -func (api *Api) SetBusinessAccountProfilePhotoStatic(p SetMyProfilePhotoP[InputProfilePhotoStatic]) (bool, error) { - req := NewRequest[bool]("setBusinessAccountProfilePhoto", p) - return req.Do(api) -} -func (api *Api) SetBusinessAccountProfilePhotoAnimated(p SetMyProfilePhotoP[InputProfilePhotoAnimated]) (bool, error) { +func (api *Api) SetBusinessAccountProfilePhoto(p SetBusinessAccountProfilePhoto) (bool, error) { req := NewRequest[bool]("setBusinessAccountProfilePhoto", p) return req.Do(api) } @@ -163,3 +159,100 @@ func (api *Api) GetBusinessAccountGifts(p GetBusinessAccountGiftsP) (OwnedGifts, req := NewRequest[OwnedGifts]("getBusinessAccountGifts", p) return req.Do(api) } + +type ConvertGiftToStarsP struct { + BusinessConnectionID string `json:"business_connection_id"` + OwnedGiftID string `json:"owned_gift_id"` +} + +func (api *Api) ConvertGiftToStars(p ConvertGiftToStarsP) (bool, error) { + req := NewRequest[bool]("convertGiftToStars", p) + return req.Do(api) +} + +type UpgradeGiftP struct { + BusinessConnectionID string `json:"business_connection_id"` + OwnedGiftID string `json:"owned_gift_id"` + KeepOriginalDetails bool `json:"keep_original_details,omitempty"` + StarCount int `json:"star_count,omitempty"` +} + +func (api *Api) UpgradeGift(p UpgradeGiftP) (bool, error) { + req := NewRequest[bool]("upgradeGift", p) + return req.Do(api) +} + +type TransferGiftP struct { + BusinessConnectionID string `json:"business_connection_id"` + OwnedGiftID string `json:"owned_gift_id"` + NewOwnerChatID int `json:"new_owner_chat_id"` + StarCount int `json:"star_count,omitempty"` +} + +func (api *Api) TransferGift(p TransferGiftP) (bool, error) { + req := NewRequest[bool]("transferGift", p) + return req.Do(api) +} + +type PostStoryP struct { + BusinessConnectionID string `json:"business_connection_id"` + Content InputStoryContent `json:"content"` + ActivePeriod int `json:"active_period"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Areas []StoryArea `json:"areas"` + + PostToChatPage bool `json:"post_to_chat_page,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` +} + +func (api *Api) PostStoryPhoto(p PostStoryP) (Story, error) { + req := NewRequest[Story]("postStory", p) + return req.Do(api) +} +func (api *Api) PostStoryVideo(p PostStoryP) (Story, error) { + req := NewRequest[Story]("postStory", p) + return req.Do(api) +} + +type RepostStoryP struct { + BusinessConnectionID string `json:"business_connection_id"` + FromChatID int `json:"from_chat_id"` + FromStoryID int `json:"from_story_id"` + ActivePeriod int `json:"active_period"` + PostToChatPage bool `json:"post_to_chat_page,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` +} + +func (api *Api) RepostStory(p RepostStoryP) (Story, error) { + req := NewRequest[Story]("repostStory", p) + return req.Do(api) +} + +type EditStoryP struct { + BusinessConnectionID string `json:"business_connection_id"` + StoryID int `json:"story_id"` + Content InputStoryContent `json:"content"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Areas []StoryArea `json:"areas,omitempty"` +} + +func (api *Api) EditStory(p EditStoryP) (Story, error) { + req := NewRequest[Story]("editStory", p) + return req.Do(api) +} + +type DeleteStoryP struct { + BusinessConnectionID string `json:"business_connection_id"` + StoryID int `json:"story_id"` +} + +func (api *Api) DeleteStory(p DeleteStoryP) (bool, error) { + req := NewRequest[bool]("deleteStory", p) + return req.Do(api) +} diff --git a/tgapi/business_types.go b/tgapi/business_types.go index 4f952de..fb9770d 100644 --- a/tgapi/business_types.go +++ b/tgapi/business_types.go @@ -42,3 +42,63 @@ type BusinessConnection struct { Rights *BusinessBotRights `json:"rights,omitempty"` IsEnabled bool `json:"id_enabled"` } + +const ( + InputStoryContentPhotoType InputStoryContentType = "photo" + InputStoryContentVideoType InputStoryContentType = "video" +) + +type InputStoryContentType string +type InputStoryContent struct { + Type InputStoryContentType `json:"type"` + // Photo + Photo *string `json:"photo,omitempty"` + + // Video + Video *string `json:"video,omitempty"` + Duration *float64 `json:"duration,omitempty"` + CoverFrameTimestamp *float64 `json:"cover_frame_timestamp,omitempty"` + IsAnimation *bool `json:"is_animation,omitempty"` +} + +type StoryAreaPosition struct { + XPercentage float64 `json:"x_percentage"` + YPercentage float64 `json:"y_percentage"` + WidthPercentage float64 `json:"width_percentage"` + HeightPercentage float64 `json:"height_percentage"` + RotationAngle float64 `json:"rotation_angle"` + CornerRadiusPercentage float64 `json:"corner_radius_percentage"` +} + +const ( + StoryAreaTypeLocationType StoryAreaTypeType = "location" + StoryAreaTypeReactionType StoryAreaTypeType = "suggested_reaction" + StoryAreaTypeLinkType StoryAreaTypeType = "link" + StoryAreaTypeWeatherType StoryAreaTypeType = "weather" + StoryAreaTypeUniqueGiftType StoryAreaTypeType = "unique_gift" +) + +type StoryAreaTypeType string +type StoryAreaType struct { + Type StoryAreaTypeType `json:"type"` + + Latitude *float64 `json:"latitude,omitempty"` + Longitude *float64 `json:"longitude,omitempty"` + Address *LocationAddress `json:"address,omitempty"` + + ReactionType *ReactionType `json:"reaction_type,omitempty"` + IsDark *bool `json:"is_dark,omitempty"` + IsFlipped *bool `json:"is_flipped,omitempty"` + + URL *string `json:"url,omitempty"` + + Temperature *float64 `json:"temperature,omitempty"` + Emoji *string `json:"emoji"` + BackgroundColor *int `json:"background_color"` + + Name *string `json:"name,omitempty"` +} +type StoryArea struct { + Position StoryAreaPosition `json:"position"` + Type StoryAreaType `json:"type"` +} diff --git a/tgapi/chat_methods.go b/tgapi/chat_methods.go index f6f4df5..386c118 100644 --- a/tgapi/chat_methods.go +++ b/tgapi/chat_methods.go @@ -1,10 +1,10 @@ package tgapi type BanChatMemberP struct { - ChatID int `json:"chat_id"` - UserID int `json:"user_id"` - UntilDate int64 `json:"until_date,omitempty"` - RevokeMessages bool `json:"revoke_messages,omitempty"` + ChatID int `json:"chat_id"` + UserID int `json:"user_id"` + UntilDate int `json:"until_date,omitempty"` + RevokeMessages bool `json:"revoke_messages,omitempty"` } func (api *Api) BanChatMember(p BanChatMemberP) (bool, error) { @@ -115,11 +115,11 @@ func (api *Api) ExportChatInviteLink(p ExportChatInviteLinkP) (string, error) { } type CreateChatInviteLinkP struct { - ChatID int `json:"chat_id"` - Name string `json:"name,omitempty"` - ExpireDate int `json:"expire_date,omitempty"` - MemberLimit int `json:"member_limit,omitempty"` - CreatesJoinRequest int `json:"creates_join_request,omitempty"` + ChatID int `json:"chat_id"` + Name *string `json:"name,omitempty"` + ExpireDate int `json:"expire_date,omitempty"` + MemberLimit int `json:"member_limit,omitempty"` + CreatesJoinRequest int `json:"creates_join_request,omitempty"` } func (api *Api) CreateChatInviteLink(p CreateChatInviteLinkP) (ChatInviteLink, error) { @@ -230,10 +230,10 @@ func (api *Api) SetChatDescription(p SetChatDescriptionP) (bool, error) { } type PinChatMessageP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageID int `json:"message_id"` - DisableNotification bool `json:"disable_notification,omitempty"` + BusinessConnectionID *string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + DisableNotification bool `json:"disable_notification,omitempty"` } func (api *Api) PinChatMessage(p PinChatMessageP) (bool, error) { @@ -242,9 +242,9 @@ func (api *Api) PinChatMessage(p PinChatMessageP) (bool, error) { } type UnpinChatMessageP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageID int `json:"message_id"` + BusinessConnectionID *string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` } func (api *Api) UnpinChatMessage(p UnpinChatMessageP) (bool, error) { @@ -283,8 +283,8 @@ type GetChatAdministratorsP struct { ChatID int `json:"chat_id"` } -func (api *Api) GetChatAdministrators(p GetChatAdministratorsP) ([]BaseChatMember, error) { - req := NewRequest[[]BaseChatMember]("getChatAdministrators", p) +func (api *Api) GetChatAdministrators(p GetChatAdministratorsP) ([]ChatMember, error) { + req := NewRequest[[]ChatMember]("getChatAdministrators", p) return req.Do(api) } @@ -302,8 +302,8 @@ type GetChatMemberP struct { UserID int `json:"user_id"` } -func (api *Api) GetChatMember(p GetChatMemberP) (BaseChatMember, error) { - req := NewRequest[BaseChatMember]("getChatMember", p) +func (api *Api) GetChatMember(p GetChatMemberP) (ChatMember, error) { + req := NewRequest[ChatMember]("getChatMember", p) return req.Do(api) } @@ -335,3 +335,22 @@ func (api *Api) GetUserChatBoosts(p GetUserChatBoostsP) (UserChatBoosts, error) req := NewRequest[UserChatBoosts]("getUserChatBoosts", p) return req.Do(api) } + +type GetChatGiftsP struct { + ChatID int `json:"chat_id"` + ExcludeUnsaved bool `json:"exclude_unsaved,omitempty"` + ExcludeSaved bool `json:"exclude_saved,omitempty"` + ExcludeUnlimited bool `json:"exclude_unlimited,omitempty"` + ExcludeLimitedUpgradable bool `json:"exclude_limited_upgradable,omitempty"` + ExcludeLimitedNonUpgradable bool `json:"exclude_limited_non_upgradable,omitempty"` + ExcludeUnique bool `json:"exclude_unique,omitempty"` + ExcludeFromBlockchain bool `json:"exclude_from_blockchain,omitempty"` + SortByPrice bool `json:"sort_by_price,omitempty"` + Offset string `json:"offset,omitempty"` + Limit int `json:"limit,omitempty"` +} + +func (api *Api) GetChatGifts(p GetChatGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getChatGifts", p) + return req.Do(api) +} diff --git a/tgapi/chat_types.go b/tgapi/chat_types.go index 1983699..e4c4e52 100644 --- a/tgapi/chat_types.go +++ b/tgapi/chat_types.go @@ -42,7 +42,7 @@ type ChatFullInfo struct { PersonalChat *Chat `json:"personal_chat,omitempty"` ParentChat *Chat `json:"parent_chat,omitempty"` - AvailableReaction []BaseReaction `json:"available_reaction,omitempty"` + AvailableReaction []ReactionType `json:"available_reaction,omitempty"` BackgroundCustomEmojiID *string `json:"background_custom_emoji_id,omitempty"` ProfileAccentColorID *int `json:"profile_accent_color_id,omitempty"` @@ -134,69 +134,47 @@ const ( ChatMemberStatusBanned ChatMemberStatusType = "kicked" ) -type ChatMember interface { - ChatMemberOwner | ChatMemberAdministrator | ChatMemberMember | ChatMemberRestricted | ChatMemberLeft | ChatMemberBanned -} -type BaseChatMember struct { +type ChatMember struct { Status ChatMemberStatusType `json:"status"` User User `json:"user"` -} -type ChatMemberOwner struct { - BaseChatMember - IsAnonymous bool `json:"is_anonymous"` + // Owner + IsAnonymous *bool `json:"is_anonymous"` CustomTitle *string `json:"custom_title,omitempty"` -} -type ChatMemberAdministrator struct { - BaseChatMember - CanBeEdited bool `json:"can_be_edited"` - IsAnonymous bool `json:"is_anonymous"` - CanManageChat bool `json:"can_manage_chat"` - CanDeleteMessages bool `json:"can_delete_messages"` - CanManageVideoChats bool `json:"can_manage_video_chats"` - CanRestrictMembers bool `json:"can_restrict_members"` - CanPromoteMembers bool `json:"can_promote_members"` - CanChangeInfo bool `json:"can_change_info"` - CanInviteUsers bool `json:"can_invite_users"` - CanPostStories bool `json:"can_post_stories"` - CanEditStories bool `json:"can_edit_stories"` - CanDeleteStories bool `json:"can_delete_stories"` - CanPostMessages *bool `json:"can_post_messages,omitempty"` - CanEditMessages *bool `json:"can_edit_messages,omitempty"` - CanPinMessages *bool `json:"can_pin_messages,omitempty"` - CanManageTopics *bool `json:"can_manage_topics,omitempty"` - CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` - CustomTitle *string `json:"custom_title,omitempty"` -} -type ChatMemberMember struct { - BaseChatMember + // Administrator + CanBeEdited *bool `json:"can_be_edited,omitempty"` + CanManageChat *bool `json:"can_manage_chat,omitempty"` + CanDeleteMessages *bool `json:"can_delete_messages,omitempty"` + CanManageVideoChats *bool `json:"can_manage_video_chats,omitempty"` + CanRestrictMembers *bool `json:"can_restrict_members,omitempty"` + CanPromoteMembers *bool `json:"can_promote_members,omitempty"` + CanChangeInfo *bool `json:"can_change_info,omitempty"` + CanInviteUsers *bool `json:"can_invite_users,omitempty"` + CanPostStories *bool `json:"can_post_stories,omitempty"` + CanEditStories *bool `json:"can_edit_stories,omitempty"` + CanDeleteStories *bool `json:"can_delete_stories,omitempty"` + + CanPostMessages *bool `json:"can_post_messages,omitempty"` + CanEditMessages *bool `json:"can_edit_messages,omitempty"` + CanPinMessages *bool `json:"can_pin_messages,omitempty"` + CanManageTopics *bool `json:"can_manage_topics,omitempty"` + CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` + + // Member UntilDate *int `json:"until_date,omitempty"` -} -type ChatMemberRestricted struct { - BaseChatMember - IsMember bool `json:"is_member"` - CanSendMessages bool `json:"can_send_messages"` - CanSendAudios bool `json:"can_send_audios"` - CanSendDocuments bool `json:"can_send_documents"` - CanSendVideos bool `json:"can_send_videos"` - CanSendVideoNotes bool `json:"can_send_video_notes"` - CanSendVoiceNotes bool `json:"can_send_voice_notes"` - CanSendPolls bool `json:"can_send_polls"` - CanSendOtherMessages bool `json:"can_send_other_messages"` - CanAddWebPagePreview bool `json:"can_add_web_page_preview"` - CanChangeInfo bool `json:"can_change_info"` - CanInviteUsers bool `json:"can_invite_users"` - CanPinMessages bool `json:"can_pin_messages"` - CanManageTopics bool `json:"can_manage_topics"` - UntilDate int `json:"until_date"` -} -type ChatMemberLeft struct { - BaseChatMember -} -type ChatMemberBanned struct { - BaseChatMember - UntilDate int `json:"until_date"` + + // Restricted + IsMember *bool `json:"is_member,omitempty"` + CanSendMessages *bool `json:"can_send_messages,omitempty"` + CanSendAudios *bool `json:"can_send_audios,omitempty"` + CanSendDocuments *bool `json:"can_send_documents,omitempty"` + CanSendVideos *bool `json:"can_send_videos,omitempty"` + CanSendVideoNotes *bool `json:"can_send_video_notes,omitempty"` + CanSendVoiceNotes *bool `json:"can_send_voice_notes,omitempty"` + CanSendPolls *bool `json:"can_send_polls,omitempty"` + CanSendOtherMessages *bool `json:"can_send_other_messages,omitempty"` + CanAddWebPagePreview *bool `json:"can_add_web_page_preview,omitempty"` } type BaseChatBoostSource struct { diff --git a/tgapi/messages_methods.go b/tgapi/messages_methods.go index e76d382..ba8a1ff 100644 --- a/tgapi/messages_methods.go +++ b/tgapi/messages_methods.go @@ -8,7 +8,7 @@ type SendMessageP struct { Text string `json:"text"` ParseMode ParseMode `json:"parse_mode,omitempty"` - Entities []*MessageEntity `json:"entities,omitempty"` + Entities []MessageEntity `json:"entities,omitempty"` LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` DisableNotifications bool `json:"disable_notifications,omitempty"` ProtectContent bool `json:"protect_content,omitempty"` @@ -72,12 +72,12 @@ type CopyMessageP struct { Caption string `json:"caption,omitempty"` ParseMode ParseMode `json:"parse_mode,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` @@ -197,7 +197,7 @@ type SendPollP struct { Question string `json:"question"` QuestionParseMode ParseMode `json:"question_mode,omitempty"` - QuestionEntities []*MessageEntity `json:"question_entities,omitempty"` + QuestionEntities []MessageEntity `json:"question_entities,omitempty"` Options []InputPollOption `json:"options"` IsAnonymous bool `json:"is_anonymous,omitempty"` Type PollType `json:"type"` @@ -205,7 +205,7 @@ type SendPollP struct { CorrectOptionID int `json:"correct_option_id,omitempty"` Explanation string `json:"explanation,omitempty"` ExplanationParseMode ParseMode `json:"explanation_parse_mode,omitempty"` - ExplanationEntities []*MessageEntity `json:"explanation_entities,omitempty"` + ExplanationEntities []MessageEntity `json:"explanation_entities,omitempty"` OpenPeriod int `json:"open_period,omitempty"` CloseDate int `json:"close_date"` IsClosed bool `json:"is_closed,omitempty"` @@ -266,12 +266,12 @@ func (api *Api) SendDice(params SendDiceP) (Message, error) { } type SendMessageDraftP struct { - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - DraftID int `json:"draft_id"` - Text string `json:"text"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Entities []*MessageEntity `json:"entities,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DraftID int `json:"draft_id"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Entities []MessageEntity `json:"entities,omitempty"` } func (api *Api) SendMessageDraft(params SendMessageDraftP) (bool, error) { @@ -291,22 +291,14 @@ func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { return req.Do(api) } -type SetMessageReactionP[T ReactionType] struct { - ChatId int `json:"chat_id"` - MessageId int `json:"message_id"` - Reaction []T `json:"reaction"` - IsBig bool `json:"is_big,omitempty"` +type SetMessageReactionP struct { + ChatId int `json:"chat_id"` + MessageId int `json:"message_id"` + Reaction []ReactionType `json:"reaction"` + IsBig bool `json:"is_big,omitempty"` } -func (api *Api) SetMessageReactionEmoji(params SetMessageReactionP[ReactionTypeEmoji]) (bool, error) { - req := NewRequest[bool]("setMessageReaction", params) - return req.Do(api) -} -func (api *Api) SetMessageReactionCustom(params SetMessageReactionP[ReactionTypeCustomEmoji]) (bool, error) { - req := NewRequest[bool]("setMessageReaction", params) - return req.Do(api) -} -func (api *Api) SetMessageReactionPaid(params SetMessageReactionP[ReactionTypePaid]) (bool, error) { +func (api *Api) SetMessageReaction(params SetMessageReactionP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) return req.Do(api) } diff --git a/tgapi/messages_types.go b/tgapi/messages_types.go index 1bb7727..7a81c33 100644 --- a/tgapi/messages_types.go +++ b/tgapi/messages_types.go @@ -190,8 +190,8 @@ type MessageReactionUpdated struct { User *User `json:"user,omitempty"` ActorChat *Chat `json:"actor_chat"` Date int `json:"date"` - OldReaction []BaseReaction `json:"old_reaction"` - NewReaction []BaseReaction `json:"new_reaction"` + OldReaction []ReactionType `json:"old_reaction"` + NewReaction []ReactionType `json:"new_reaction"` } type MessageReactionCountUpdated struct { @@ -200,26 +200,15 @@ type MessageReactionCountUpdated struct { Date int `json:"date"` Reactions []*ReactionCount `json:"reactions"` } - -type ReactionType interface { - ReactionTypeEmoji | ReactionTypeCustomEmoji | ReactionTypePaid -} -type BaseReaction struct { - Type string `json:"type"` -} -type ReactionTypeEmoji struct { - Type string `json:"type"` - Emoji string `json:"emoji"` -} -type ReactionTypeCustomEmoji struct { - Type string `json:"type"` - CustomEmojiID string `json:"custom_emoji_id"` -} -type ReactionTypePaid struct { +type ReactionType struct { Type string `json:"type"` + // ReactionTypeEmoji + Emoji *string `json:"emoji,omitempty"` + // ReactionTypeCustomEmoji + CustomEmojiID *string `json:"custom_emoji_id,omitempty"` } type ReactionCount struct { - Type BaseReaction `json:"type"` + Type ReactionType `json:"type"` TotalCount int `json:"total_count"` } diff --git a/tgapi/types.go b/tgapi/types.go index e400341..5322cce 100644 --- a/tgapi/types.go +++ b/tgapi/types.go @@ -1,20 +1,85 @@ package tgapi type Update struct { - UpdateID int `json:"update_id"` - Message *Message `json:"message"` - EditedMessage *Message `json:"edited_message,omitempty"` - ChannelPost *Message `json:"channel_post,omitempty"` - EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + UpdateID int `json:"update_id"` + Message *Message `json:"message,omitempty"` + EditedMessage *Message `json:"edited_message,omitempty"` + ChannelPost *Message `json:"channel_post,omitempty"` + EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + BusinessConnection *BusinessConnection `json:"business_connection,omitempty"` BusinessMessage *Message `json:"business_message,omitempty"` EditedBusinessMessage *Message `json:"edited_business_message,omitempty"` DeletedBusinessMessage *Message `json:"deleted_business_messages,omitempty"` MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"` MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"` - CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` - InlineQuery int - ChosenInlineResult int + + InlineQuery *InlineQuery `json:"inline_query,omitempty"` + ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"` + CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` + ShippingQuery ShippingQuery `json:"shipping_query,omitempty"` + PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` + PurchasedPaidMedia *PaidMediaPurchased `json:"purchased_paid_media,omitempty"` + + Poll any `json:"poll,omitempty"` + PollAnswer any `json:"poll_answer,omitempty"` + MyChatMember any `json:"my_chat_member,omitempty"` + ChatMember any `json:"chat_member,omitempty"` + ChatJoinRequest any `json:"chat_join_request,omitempty"` + ChatBoost any `json:"chat_boost,omitempty"` + RemovedChatBoost any `json:"removed_chat_boost,omitempty"` +} + +type InlineQuery struct { + ID string `json:"id"` + From User `json:"from"` + Query string `json:"query"` + Offset string `json:"offset"` + ChatType *ChatType `json:"chat_type,omitempty"` + Location *Location `json:"location,omitempty"` +} +type ChosenInlineResult struct { + ResultID string `json:"result_id"` + From User `json:"from"` + Location *Location `json:"location,omitempty"` + InlineMessageID string `json:"inline_message_id"` + Query string `json:"query"` +} + +type ShippingQuery struct { + ID string `json:"id"` + From User `json:"from"` + InvoicePayload string `json:"invoice_payload"` + ShippingAddress ShippingAddress `json:"shipping_address"` +} +type ShippingAddress struct { + CountryCode string `json:"country_code"` + State string `json:"state"` + City string `json:"city"` + StreetLine1 string `json:"street_line1"` + StreetLine2 string `json:"street_line2"` + PostCode string `json:"post_code"` +} + +type OrderInfo struct { + Name string `json:"name"` + PhoneNumber string `json:"phone_number"` + Email string `json:"email"` + ShippingAddress ShippingAddress `json:"shipping_address"` +} +type PreCheckoutQuery struct { + ID string `json:"id"` + From User `json:"from"` + Currency string `json:"currency"` + TotalAmount int `json:"total_amount"` + InvoicePayload string `json:"invoice_payload"` + ShippingOptionID string `json:"shipping_option_id"` + OrderInfo *OrderInfo `json:"order_info,omitempty"` +} + +type PaidMediaPurchased struct { + From User `json:"from"` + PaidMediaPayload string `json:"paid_media_payload"` } type File struct { @@ -45,6 +110,12 @@ type Location struct { Heading int `json:"heading"` ProximityAlertRadius int `json:"proximity_alert_radius"` } +type LocationAddress struct { + CountryCode string `json:"country_code"` + State *string `json:"state,omitempty"` + City *string `json:"city,omitempty"` + Street *string `json:"street,omitempty"` +} type Venue struct { Location Location `json:"location"` Title string `json:"title"` @@ -64,6 +135,11 @@ type StarAmount struct { NanostarAmount int `json:"nanostar_amount"` } +type Story struct { + Chat Chat `json:"chat"` + ID int `json:"id"` +} + // Gifts type AcceptedGiftTypes struct { diff --git a/tgapi/users_methods.go b/tgapi/users_methods.go index d54d496..24cb024 100644 --- a/tgapi/users_methods.go +++ b/tgapi/users_methods.go @@ -32,3 +32,20 @@ func (api *Api) SetUserEmojiStatus(p SetUserEmojiStatusP) (bool, error) { req := NewRequest[bool]("setUserEmojiStatus", p) return req.Do(api) } + +type GetUserGiftsP struct { + UserID int `json:"user_id"` + ExcludeUnlimited bool `json:"exclude_unlimited,omitempty"` + ExcludeLimitedUpgradable bool `json:"exclude_limited_upgradable,omitempty"` + ExcludeLimitedNonUpgradable bool `json:"exclude_limited_non_upgradable,omitempty"` + ExcludeUnique bool `json:"exclude_unique,omitempty"` + ExcludeFromBlockchain bool `json:"exclude_from_blockchain,omitempty"` + SortByPrice bool `json:"sort_by_price,omitempty"` + Offset string `json:"offset,omitempty"` + Limit int `json:"limit,omitempty"` +} + +func (api *Api) GetUserGifts(p GetUserGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getUserGifts", p) + return req.Do(api) +} diff --git a/tgapi/users_types.go b/tgapi/users_types.go index 9c674c1..b826074 100644 --- a/tgapi/users_types.go +++ b/tgapi/users_types.go @@ -1,21 +1,21 @@ package tgapi type User struct { - ID int `json:"id"` - IsBot bool `json:"is_bot"` - FirstName string `json:"first_name"` - LastName string `json:"last_name,omitempty"` - Username string `json:"username,omitempty"` - LanguageCode string `json:"language_code,omitempty"` - IsPremium bool `json:"is_premium,omitempty"` - AddedToAttachmentMenu bool `json:"added_to_attachment_menu,omitempty"` - CanJoinGroups bool `json:"can_join_groups,omitempty"` - CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"` - SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"` - CanConnectToBusiness bool `json:"can_connect_to_business,omitempty"` - HasMainWebApp bool `json:"has_main_web_app,omitempty"` - HasTopicsEnabled bool `json:"has_topics_enabled,omitempty"` - AllowsUsersToCreateTopics bool `json:"allows_users_to_create_topics,omitempty"` + ID int `json:"id"` + IsBot bool `json:"is_bot"` + FirstName string `json:"first_name"` + LastName *string `json:"last_name,omitempty"` + Username *string `json:"username,omitempty"` + LanguageCode *string `json:"language_code,omitempty"` + IsPremium *bool `json:"is_premium,omitempty"` + AddedToAttachmentMenu *bool `json:"added_to_attachment_menu,omitempty"` + CanJoinGroups *bool `json:"can_join_groups,omitempty"` + CanReadAllGroupMessages *bool `json:"can_read_all_group_messages,omitempty"` + SupportsInlineQueries *bool `json:"supports_inline_queries,omitempty"` + CanConnectToBusiness *bool `json:"can_connect_to_business,omitempty"` + HasMainWebApp *bool `json:"has_main_web_app,omitempty"` + HasTopicsEnabled *bool `json:"has_topics_enabled,omitempty"` + AllowsUsersToCreateTopics *bool `json:"allows_users_to_create_topics,omitempty"` } type UserProfilePhotos struct { -- 2.53.0 From a5ca836fa463455a6f1d432ea98a671f778b9ae8 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 11 Feb 2026 23:05:10 +0300 Subject: [PATCH 13/16] WIP v0.5.0 --- tgapi/chat_types.go | 40 ++++++++++++-------- tgapi/methods.go | 7 ++-- tgapi/types.go | 92 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 25 deletions(-) diff --git a/tgapi/chat_types.go b/tgapi/chat_types.go index e4c4e52..7b1ea6e 100644 --- a/tgapi/chat_types.go +++ b/tgapi/chat_types.go @@ -177,26 +177,24 @@ type ChatMember struct { CanAddWebPagePreview *bool `json:"can_add_web_page_preview,omitempty"` } -type BaseChatBoostSource struct { +type ChatBoostSource struct { Source string `json:"source"` User User `json:"user"` + + // Giveaway + GiveawayMessageID *int `json:"giveaway_message_id,omitempty"` + PrizeStarCount *int `json:"prize_star_count,omitempty"` + IsUnclaimed *bool `json:"is_unclaimed,omitempty"` } -type ChatBoostSourcePremium struct{ BaseChatBoostSource } -type ChatBoostSourceGiftCode struct{ BaseChatBoostSource } -type ChatBoostSourceGiveaway struct { - BaseChatBoostSource - GiveawayMessageID int `json:"giveaway_message_id"` - PrizeStarCount *int `json:"prize_star_count,omitempty"` - IsUnclaimed bool `json:"is_unclaimed"` -} -type ChatBoost[T BaseChatBoostSource] struct { - BoostID int `json:"boost_id"` - AddDate int `json:"add_date"` - ExpirationDate int `json:"expiration_date"` - Source T `json:"source"` + +type ChatBoost struct { + BoostID int `json:"boost_id"` + AddDate int `json:"add_date"` + ExpirationDate int `json:"expiration_date"` + Source ChatBoostSource `json:"source"` } type UserChatBoosts struct { - Boosts []ChatBoost[BaseChatBoostSource] `json:"boosts"` + Boosts []ChatBoost `json:"boosts"` } type ChatAdministratorRights struct { @@ -218,3 +216,15 @@ type ChatAdministratorRights struct { CanManageTopics *bool `json:"can_manage_topics,omitempty"` CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` } + +type ChatBoostUpdated struct { + Chat Chat `json:"chat"` + Boost ChatBoost `json:"boost"` +} + +type ChatBoostRemoved struct { + Chat Chat `json:"chat"` + BoostID string `json:"boost_id"` + RemoveDate int `json:"remove_date"` + Source ChatBoostSource `json:"source"` +} diff --git a/tgapi/methods.go b/tgapi/methods.go index b000089..c75e2e8 100644 --- a/tgapi/methods.go +++ b/tgapi/methods.go @@ -13,9 +13,10 @@ type EmptyParams struct{} var NoParams = EmptyParams{} type UpdateParams struct { - Offset int `json:"offset"` - Timeout int `json:"timeout"` - AllowedUpdates []string `json:"allowed_updates"` + Offset *int `json:"offset,omitempty"` + Limit *int `json:"limit,omitempty"` + Timeout *int `json:"timeout,omitempty"` + AllowedUpdates []UpdateType `json:"allowed_updates"` } func (api *Api) GetMe() (User, error) { diff --git a/tgapi/types.go b/tgapi/types.go index 5322cce..6143a63 100644 --- a/tgapi/types.go +++ b/tgapi/types.go @@ -1,5 +1,35 @@ package tgapi +type UpdateType string + +const ( + UpdateTypeMessage UpdateType = "message" + UpdateTypeEditedMessage UpdateType = "edited_message" + UpdateTypeChannelPost UpdateType = "channel_post" + UpdateTypeEditedChannelPost UpdateType = "edited_channel_post" + UpdateTypeMessageReaction UpdateType = "message_reaction" + UpdateTypeMessageReactionCount UpdateType = "message_reaction_count" + + UpdateTypeBusinessConnection UpdateType = "business_connection" + UpdateTypeBusinessMessage UpdateType = "business_message" + UpdateTypeEditedBusinessMessage UpdateType = "edited_business_message" + UpdateTypeDeletedBusinessMessage UpdateType = "deleted_business_message" + + UpdateTypeInlineQuery UpdateType = "inline_query" + UpdateTypeChosenInlineResult UpdateType = "chosen_inline_result" + UpdateTypeCallbackQuery UpdateType = "callback_query" + UpdateTypeShippingQuery UpdateType = "shipping_query" + UpdateTypePreCheckoutQuery UpdateType = "pre_checkout_query" + UpdateTypePurchasedPaidMedia UpdateType = "purchased_paid_media" + UpdateTypePoll UpdateType = "poll" + UpdateTypePollAnswer UpdateType = "poll_answer" + UpdateTypeMyChatMember UpdateType = "my_chat_member" + UpdateTypeChatMember UpdateType = "chat_member" + UpdateTypeChatJoinRequest UpdateType = "chat_join_request" + UpdateTypeChatBoost UpdateType = "chat_boost" + UpdateTypeRemovedChatBoost UpdateType = "removed_chat_boost" +) + type Update struct { UpdateID int `json:"update_id"` Message *Message `json:"message,omitempty"` @@ -21,13 +51,13 @@ type Update struct { PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` PurchasedPaidMedia *PaidMediaPurchased `json:"purchased_paid_media,omitempty"` - Poll any `json:"poll,omitempty"` - PollAnswer any `json:"poll_answer,omitempty"` - MyChatMember any `json:"my_chat_member,omitempty"` - ChatMember any `json:"chat_member,omitempty"` - ChatJoinRequest any `json:"chat_join_request,omitempty"` - ChatBoost any `json:"chat_boost,omitempty"` - RemovedChatBoost any `json:"removed_chat_boost,omitempty"` + Poll *Poll `json:"poll,omitempty"` + PollAnswer *PollAnswer `json:"poll_answer,omitempty"` + MyChatMember *ChatMemberUpdated `json:"my_chat_member,omitempty"` + ChatMember *ChatMemberUpdated `json:"chat_member,omitempty"` + ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"` + ChatBoost *ChatBoostUpdated `json:"chat_boost,omitempty"` + RemovedChatBoost *ChatBoostRemoved `json:"removed_chat_boost,omitempty"` } type InlineQuery struct { @@ -102,6 +132,54 @@ type Audio struct { Thumbnail *PhotoSize `json:"thumbnail,omitempty"` } +type PollOption struct { + Text string `json:"text"` + TextEntities []MessageEntity `json:"text_entities"` + VoterCount int `json:"voter_count"` +} +type Poll struct { + ID string `json:"id"` + Question string `json:"question"` + QuestionEntities []MessageEntity `json:"question_entities"` + Options []PollOption `json:"options"` + TotalVoterCount int `json:"total_voter_count"` + IsClosed bool `json:"is_closed"` + IsAnonymous bool `json:"is_anonymous"` + Type PollType `json:"type"` + + AllowsMultipleAnswers bool `json:"allows_multiple_answers"` + CorrectOptionID *int `json:"correct_option_id,omitempty"` + Explanation *string `json:"explanation,omitempty"` + ExplanationEntities []MessageEntity `json:"explanation_entities,omitempty"` + OpenPeriod int `json:"open_period,omitempty"` + CloseDate int `json:"close_date,omitempty"` +} +type PollAnswer struct { + PollID string `json:"poll_id"` + VoterChat Chat `json:"voter_chat"` + User User `json:"user"` + OptionIDS []int `json:"option_ids"` +} +type ChatMemberUpdated struct { + Chat Chat `json:"chat"` + From User `json:"from"` + Date int64 `json:"date"` + OldChatMember ChatMember `json:"old_chat_member"` + NewChatMember ChatMember `json:"new_chat_member"` + InviteLink *ChatInviteLink `json:"invite_link,omitempty"` + ViaJoinRequest *bool `json:"via_join_request,omitempty"` + ViaChatFolderInviteLink *bool `json:"via_chat_folder_invite_link,omitempty"` +} + +type ChatJoinRequest struct { + Chat Chat `json:"chat"` + From User `json:"from"` + UserChatID int `json:"user_chat_id"` + Date int64 `json:"date"` + Bio *string `json:"bio,omitempty"` + InviteLink *ChatInviteLink `json:"invite_link,omitempty"` +} + type Location struct { Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` -- 2.53.0 From 6c989b2cc8d025645c2f182a8e1373855797f0f0 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Thu, 12 Feb 2026 11:16:01 +0300 Subject: [PATCH 14/16] WIP v0.5.0 --- bot.go | 14 +- handler.go | 4 +- methods.go | 15 +- msg_context.go | 18 +-- tgapi/attachments_methods.go | 8 +- tgapi/bot_methods.go | 64 ++++---- tgapi/business_methods.go | 92 +++++------ tgapi/chat_methods.go | 124 +++++++-------- tgapi/forum_methods.go | 48 +++--- tgapi/messages_methods.go | 183 +++++++++++++++++++++- tgapi/methods.go | 4 + tgapi/stickers_methods.go | 60 ++++---- tgapi/uploader.go | 288 +++++++++++++++++++++++++++++------ tgapi/users_methods.go | 16 +- 14 files changed, 651 insertions(+), 287 deletions(-) diff --git a/bot.go b/bot.go index e92db57..884a3e2 100644 --- a/bot.go +++ b/bot.go @@ -35,13 +35,13 @@ type Bot struct { dbWriterRequested extypes.Slice[*slog.Logger] updateOffset int - updateTypes []string + updateTypes []tgapi.UpdateType updateQueue *extypes.Queue[*tgapi.Update] } func (b *Bot) GetUpdateOffset() int { return b.updateOffset } func (b *Bot) SetUpdateOffset(offset int) { b.updateOffset = offset } -func (b *Bot) GetUpdateTypes() []string { return b.updateTypes } +func (b *Bot) GetUpdateTypes() []tgapi.UpdateType { return b.updateTypes } func (b *Bot) GetQueue() *extypes.Queue[*tgapi.Update] { return b.updateQueue } type BotSettings struct { @@ -79,7 +79,7 @@ func NewBot(settings *BotSettings) *Bot { api := tgapi.NewAPI(settings.Token) bot := &Bot{ updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s", - prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0), + prefixes: settings.Prefixes, updateTypes: make([]tgapi.UpdateType, 0), runners: make([]Runner, 0), updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0), token: settings.Token, } @@ -163,12 +163,12 @@ func (b *Bot) DatabaseContext(ctx *DatabaseContext) *Bot { b.dbContext = ctx return b } -func (b *Bot) UpdateTypes(t ...string) *Bot { - b.updateTypes = make([]string, 0) +func (b *Bot) UpdateTypes(t ...tgapi.UpdateType) *Bot { + b.updateTypes = make([]tgapi.UpdateType, 0) b.updateTypes = append(b.updateTypes, t...) return b } -func (b *Bot) AddUpdateType(t ...string) *Bot { +func (b *Bot) AddUpdateType(t ...tgapi.UpdateType) *Bot { b.updateTypes = append(b.updateTypes, t...) return b } @@ -257,7 +257,7 @@ func (b *Bot) Run() { continue } - ctx := &MsgContext{Bot: b, Update: u, Api: b.api} + ctx := &MsgContext{Bot: b, Update: *u, Api: b.api} for _, middleware := range b.middlewares { middleware.Execute(ctx, b.dbContext) } diff --git a/handler.go b/handler.go index 464161c..064f96e 100644 --- a/handler.go +++ b/handler.go @@ -71,8 +71,8 @@ func (b *Bot) handleCallback(update *tgapi.Update, ctx *MsgContext) { } ctx.FromID = update.CallbackQuery.From.ID - ctx.From = update.CallbackQuery.From - ctx.Msg = update.CallbackQuery.Message + ctx.From = &update.CallbackQuery.From + ctx.Msg = &update.CallbackQuery.Message ctx.CallbackMsgId = update.CallbackQuery.Message.MessageID ctx.CallbackQueryId = update.CallbackQuery.ID ctx.Args = data.Args diff --git a/methods.go b/methods.go index f2b240b..d2a1f10 100644 --- a/methods.go +++ b/methods.go @@ -9,23 +9,22 @@ import ( "git.nix13.pw/scuroneko/laniakea/tgapi" ) -func (b *Bot) Updates() ([]*tgapi.Update, error) { +func (b *Bot) Updates() ([]tgapi.Update, error) { offset := b.GetUpdateOffset() params := tgapi.UpdateParams{ - Offset: offset, - Timeout: 30, + Offset: Ptr(offset), + Timeout: Ptr(30), AllowedUpdates: b.GetUpdateTypes(), } - req := tgapi.NewRequest[[]*tgapi.Update]("getUpdates", params) - res, err := req.Do(b.api) + updates, err := b.api.GetUpdates(params) if err != nil { return nil, err } - for _, u := range *res { + for _, u := range updates { b.SetUpdateOffset(u.UpdateID + 1) - err = b.GetQueue().Enqueue(u) + err = b.GetQueue().Enqueue(&u) if err != nil { return nil, err } @@ -38,7 +37,7 @@ func (b *Bot) Updates() ([]*tgapi.Update, error) { b.RequestLogger.Debugf("UPDATE %s\n", j) } } - return *res, err + return updates, err } func (b *Bot) GetFileByLink(link string) ([]byte, error) { diff --git a/msg_context.go b/msg_context.go index 922ba4f..d19274f 100644 --- a/msg_context.go +++ b/msg_context.go @@ -12,7 +12,7 @@ type MsgContext struct { Api *tgapi.Api Msg *tgapi.Message - Update *tgapi.Update + Update tgapi.Update From *tgapi.User CallbackMsgId int CallbackQueryId string @@ -31,7 +31,7 @@ type AnswerMessage struct { } func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard) *AnswerMessage { - params := &tgapi.EditMessageTextP{ + params := tgapi.EditMessageTextP{ MessageID: messageId, ChatID: ctx.Msg.Chat.ID, Text: text, @@ -40,7 +40,7 @@ func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard if keyboard != nil { params.ReplyMarkup = keyboard.Get() } - msg, err := ctx.Api.EditMessageText(params) + msg, _, err := ctx.Api.EditMessageText(params) if err != nil { ctx.Api.Logger.Errorln(err) return nil @@ -65,7 +65,7 @@ func (ctx *MsgContext) EditCallbackf(format string, keyboard *InlineKeyboard, ar } func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeyboard) *AnswerMessage { - params := &tgapi.EditMessageCaptionP{ + params := tgapi.EditMessageCaptionP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, Caption: text, @@ -74,7 +74,7 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo if kb != nil { params.ReplyMarkup = kb.Get() } - msg, err := ctx.Api.EditMessageCaption(params) + msg, _, err := ctx.Api.EditMessageCaption(params) if err != nil { ctx.Api.Logger.Errorln(err) } @@ -94,7 +94,7 @@ func (m *AnswerMessage) EditCaptionKeyboard(text string, kb *InlineKeyboard) *An } func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMessage { - params := &tgapi.SendMessageP{ + params := tgapi.SendMessageP{ ChatID: ctx.Msg.Chat.ID, Text: text, ParseMode: tgapi.ParseMD, @@ -123,7 +123,7 @@ func (ctx *MsgContext) Keyboard(text string, kb *InlineKeyboard) *AnswerMessage } func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *AnswerMessage { - params := &tgapi.SendPhotoP{ + params := tgapi.SendPhotoP{ ChatID: ctx.Msg.Chat.ID, Caption: text, ParseMode: tgapi.ParseMD, @@ -151,7 +151,7 @@ func (ctx *MsgContext) AnswerPhotoKeyboard(photoId, text string, kb *InlineKeybo } func (ctx *MsgContext) delete(messageId int) { - _, err := ctx.Api.DeleteMessage(&tgapi.DeleteMessageP{ + _, err := ctx.Api.DeleteMessage(tgapi.DeleteMessageP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, }) @@ -170,7 +170,7 @@ func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) { if len(ctx.CallbackQueryId) == 0 { return } - _, err := ctx.Api.AnswerCallbackQuery(&tgapi.AnswerCallbackQueryP{ + _, err := ctx.Api.AnswerCallbackQuery(tgapi.AnswerCallbackQueryP{ CallbackQueryID: ctx.CallbackQueryId, Text: text, ShowAlert: showAlert, URL: url, }) diff --git a/tgapi/attachments_methods.go b/tgapi/attachments_methods.go index 9241a68..2e38771 100644 --- a/tgapi/attachments_methods.go +++ b/tgapi/attachments_methods.go @@ -144,8 +144,8 @@ type SendAnimationP struct { ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` } -func (api *Api) SendAnimation(p SendAnimationP) (Message, error) { - req := NewRequest[Message]("sendAnimation", p) +func (api *Api) SendAnimation(params SendAnimationP) (Message, error) { + req := NewRequest[Message]("sendAnimation", params) return req.Do(api) } @@ -240,7 +240,7 @@ type SendMediaGroupP struct { ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` } -func (api *Api) SendMediaGroup(p SendMediaGroupP) (Message, error) { - req := NewRequest[Message]("sendMediaGroup", p) +func (api *Api) SendMediaGroup(params SendMediaGroupP) (Message, error) { + req := NewRequest[Message]("sendMediaGroup", params) return req.Do(api) } diff --git a/tgapi/bot_methods.go b/tgapi/bot_methods.go index 97e72b8..05741ae 100644 --- a/tgapi/bot_methods.go +++ b/tgapi/bot_methods.go @@ -6,8 +6,8 @@ type SetMyCommandsP struct { Language string `json:"language_code,omitempty"` } -func (api *Api) SetMyCommands(p SetMyCommandsP) (bool, error) { - req := NewRequest[bool]("setMyCommands", p) +func (api *Api) SetMyCommands(params SetMyCommandsP) (bool, error) { + req := NewRequest[bool]("setMyCommands", params) return req.Do(api) } @@ -16,8 +16,8 @@ type DeleteMyCommandsP struct { Language string `json:"language_code,omitempty"` } -func (api *Api) DeleteMyCommands(p DeleteMyCommandsP) (bool, error) { - req := NewRequest[bool]("deleteMyCommands", p) +func (api *Api) DeleteMyCommands(params DeleteMyCommandsP) (bool, error) { + req := NewRequest[bool]("deleteMyCommands", params) return req.Do(api) } @@ -26,8 +26,8 @@ type GetMyCommands struct { Language string `json:"language_code,omitempty"` } -func (api *Api) GetMyCommands(p GetMyCommands) ([]BotCommand, error) { - req := NewRequest[[]BotCommand]("getMyCommands", p) +func (api *Api) GetMyCommands(params GetMyCommands) ([]BotCommand, error) { + req := NewRequest[[]BotCommand]("getMyCommands", params) return req.Do(api) } @@ -36,8 +36,8 @@ type SetMyName struct { Language string `json:"language_code,omitempty"` } -func (api *Api) SetMyName(p SetMyName) (bool, error) { - req := NewRequest[bool]("setMyName", p) +func (api *Api) SetMyName(params SetMyName) (bool, error) { + req := NewRequest[bool]("setMyName", params) return req.Do(api) } @@ -45,8 +45,8 @@ type GetMyName struct { Language string `json:"language_code,omitempty"` } -func (api *Api) GetMyName(p GetMyName) (BotName, error) { - req := NewRequest[BotName]("getMyName", p) +func (api *Api) GetMyName(params GetMyName) (BotName, error) { + req := NewRequest[BotName]("getMyName", params) return req.Do(api) } @@ -55,8 +55,8 @@ type SetMyDescription struct { Language string `json:"language_code,omitempty"` } -func (api *Api) SetMyDescription(p SetMyDescription) (bool, error) { - req := NewRequest[bool]("setMyDescription", p) +func (api *Api) SetMyDescription(params SetMyDescription) (bool, error) { + req := NewRequest[bool]("setMyDescription", params) return req.Do(api) } @@ -64,8 +64,8 @@ type GetMyDescription struct { Language string `json:"language_code,omitempty"` } -func (api *Api) GetMyDescription(p GetMyDescription) (BotDescription, error) { - req := NewRequest[BotDescription]("getMyDescription", p) +func (api *Api) GetMyDescription(params GetMyDescription) (BotDescription, error) { + req := NewRequest[BotDescription]("getMyDescription", params) return req.Do(api) } @@ -74,8 +74,8 @@ type SetMyShortDescription struct { Language string `json:"language_code,omitempty"` } -func (api *Api) SetMyShortDescription(p SetMyShortDescription) (bool, error) { - req := NewRequest[bool]("setMyShortDescription", p) +func (api *Api) SetMyShortDescription(params SetMyShortDescription) (bool, error) { + req := NewRequest[bool]("setMyShortDescription", params) return req.Do(api) } @@ -83,8 +83,8 @@ type GetMyShortDescription struct { Language string `json:"language_code,omitempty"` } -func (api *Api) GetMyShortDescription(p GetMyShortDescription) (BotShortDescription, error) { - req := NewRequest[BotShortDescription]("getMyShortDescription", p) +func (api *Api) GetMyShortDescription(params GetMyShortDescription) (BotShortDescription, error) { + req := NewRequest[BotShortDescription]("getMyShortDescription", params) return req.Do(api) } @@ -92,8 +92,8 @@ type SetMyProfilePhotoP struct { Photo InputProfilePhoto `json:"photo"` } -func (api *Api) SetMyProfilePhoto(p SetMyProfilePhotoP) (bool, error) { - req := NewRequest[bool]("setMyProfilePhoto", p) +func (api *Api) SetMyProfilePhoto(params SetMyProfilePhotoP) (bool, error) { + req := NewRequest[bool]("setMyProfilePhoto", params) return req.Do(api) } func (api *Api) RemoveMyProfilePhoto() (bool, error) { @@ -106,8 +106,8 @@ type SetChatMenuButtonP struct { MenuButton MenuButtonType `json:"menu_button"` } -func (api *Api) SetChatMenuButton(p SetChatMenuButtonP) (bool, error) { - req := NewRequest[bool]("setChatMenuButton", p) +func (api *Api) SetChatMenuButton(params SetChatMenuButtonP) (bool, error) { + req := NewRequest[bool]("setChatMenuButton", params) return req.Do(api) } @@ -115,8 +115,8 @@ type GetChatMenuButtonP struct { ChatID int `json:"chat_id"` } -func (api *Api) GetChatMenuButton(p GetChatMenuButtonP) (BaseMenuButton, error) { - req := NewRequest[BaseMenuButton]("getChatMenuButton", p) +func (api *Api) GetChatMenuButton(params GetChatMenuButtonP) (BaseMenuButton, error) { + req := NewRequest[BaseMenuButton]("getChatMenuButton", params) return req.Do(api) } @@ -125,8 +125,8 @@ type SetMyDefaultAdministratorRightsP struct { ForChannels bool `json:"for_channels"` } -func (api *Api) SetMyDefaultAdministratorRights(p SetMyDefaultAdministratorRightsP) (bool, error) { - req := NewRequest[bool]("setMyDefaultAdministratorRights", p) +func (api *Api) SetMyDefaultAdministratorRights(params SetMyDefaultAdministratorRightsP) (bool, error) { + req := NewRequest[bool]("setMyDefaultAdministratorRights", params) return req.Do(api) } @@ -134,8 +134,8 @@ type GetMyDefaultAdministratorRightsP struct { ForChannels bool `json:"for_channels"` } -func (api *Api) GetMyDefaultAdministratorRights(p GetMyDefaultAdministratorRightsP) (ChatAdministratorRights, error) { - req := NewRequest[ChatAdministratorRights]("getMyDefaultAdministratorRights", p) +func (api *Api) GetMyDefaultAdministratorRights(params GetMyDefaultAdministratorRightsP) (ChatAdministratorRights, error) { + req := NewRequest[ChatAdministratorRights]("getMyDefaultAdministratorRights", params) return req.Do(api) } @@ -154,8 +154,8 @@ type SendGiftP struct { TextEntities []MessageEntity `json:"text_entities,omitempty"` } -func (api *Api) SendGift(p SendGiftP) (bool, error) { - req := NewRequest[bool]("sendGift", p) +func (api *Api) SendGift(params SendGiftP) (bool, error) { + req := NewRequest[bool]("sendGift", params) return req.Do(api) } @@ -168,7 +168,7 @@ type GiftPremiumSubscriptionP struct { TextEntities []MessageEntity `json:"text_entities,omitempty"` } -func (api *Api) GiftPremiumSubscription(p GiftPremiumSubscriptionP) (bool, error) { - req := NewRequest[bool]("giftPremiumSubscription", p) +func (api *Api) GiftPremiumSubscription(params GiftPremiumSubscriptionP) (bool, error) { + req := NewRequest[bool]("giftPremiumSubscription", params) return req.Do(api) } diff --git a/tgapi/business_methods.go b/tgapi/business_methods.go index fcc4660..ff6792c 100644 --- a/tgapi/business_methods.go +++ b/tgapi/business_methods.go @@ -5,8 +5,8 @@ type VerifyUserP struct { CustomDescription string `json:"custom_description,omitempty"` } -func (api *Api) VerifyUser(p VerifyUserP) (bool, error) { - req := NewRequest[bool]("verifyUser", p) +func (api *Api) VerifyUser(params VerifyUserP) (bool, error) { + req := NewRequest[bool]("verifyUser", params) return req.Do(api) } @@ -15,8 +15,8 @@ type VerifyChatP struct { CustomDescription string `json:"custom_description,omitempty"` } -func (api *Api) VerifyChat(p VerifyChatP) (bool, error) { - req := NewRequest[bool]("verifyChat", p) +func (api *Api) VerifyChat(params VerifyChatP) (bool, error) { + req := NewRequest[bool]("verifyChat", params) return req.Do(api) } @@ -24,8 +24,8 @@ type RemoveUserVerificationP struct { UserID int `json:"user_id"` } -func (api *Api) RemoveUserVerification(p RemoveUserVerificationP) (bool, error) { - req := NewRequest[bool]("removeUserVerification", p) +func (api *Api) RemoveUserVerification(params RemoveUserVerificationP) (bool, error) { + req := NewRequest[bool]("removeUserVerification", params) return req.Do(api) } @@ -33,8 +33,8 @@ type RemoveChatVerificationP struct { ChatID int `json:"chat_id"` } -func (api *Api) RemoveChatVerification(p RemoveChatVerificationP) (bool, error) { - req := NewRequest[bool]("removeChatVerification", p) +func (api *Api) RemoveChatVerification(params RemoveChatVerificationP) (bool, error) { + req := NewRequest[bool]("removeChatVerification", params) return req.Do(api) } @@ -44,8 +44,8 @@ type ReadBusinessMessageP struct { MessageID int `json:"message_id"` } -func (api *Api) ReadBusinessMessage(p ReadBusinessMessageP) (bool, error) { - req := NewRequest[bool]("readBusinessMessage", p) +func (api *Api) ReadBusinessMessage(params ReadBusinessMessageP) (bool, error) { + req := NewRequest[bool]("readBusinessMessage", params) return req.Do(api) } @@ -54,8 +54,8 @@ type DeleteBusinessMessageP struct { MessageIDs []int `json:"message_ids"` } -func (api *Api) DeleteBusinessMessage(p DeleteBusinessMessageP) (bool, error) { - req := NewRequest[bool]("deleteBusinessMessage", p) +func (api *Api) DeleteBusinessMessage(params DeleteBusinessMessageP) (bool, error) { + req := NewRequest[bool]("deleteBusinessMessage", params) return req.Do(api) } @@ -65,8 +65,8 @@ type SetBusinessAccountNameP struct { LastName string `json:"last_name,omitempty"` } -func (api *Api) SetBusinessAccountName(p SetBusinessAccountNameP) (bool, error) { - req := NewRequest[bool]("setBusinessAccountName", p) +func (api *Api) SetBusinessAccountName(params SetBusinessAccountNameP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountName", params) return req.Do(api) } @@ -75,8 +75,8 @@ type SetBusinessAccountUsernameP struct { Username string `json:"username,omitempty"` } -func (api *Api) SetBusinessAccountUsername(p SetBusinessAccountUsernameP) (bool, error) { - req := NewRequest[bool]("setBusinessAccountUsername", p) +func (api *Api) SetBusinessAccountUsername(params SetBusinessAccountUsernameP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountUsername", params) return req.Do(api) } @@ -85,8 +85,8 @@ type SetBusinessAccountBioP struct { Bio string `json:"bio,omitempty"` } -func (api *Api) SetBusinessAccountBio(p SetBusinessAccountBioP) (bool, error) { - req := NewRequest[bool]("setBusinessAccountBio", p) +func (api *Api) SetBusinessAccountBio(params SetBusinessAccountBioP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountBio", params) return req.Do(api) } @@ -96,8 +96,8 @@ type SetBusinessAccountProfilePhoto struct { IsPublic bool `json:"is_public,omitempty"` } -func (api *Api) SetBusinessAccountProfilePhoto(p SetBusinessAccountProfilePhoto) (bool, error) { - req := NewRequest[bool]("setBusinessAccountProfilePhoto", p) +func (api *Api) SetBusinessAccountProfilePhoto(params SetBusinessAccountProfilePhoto) (bool, error) { + req := NewRequest[bool]("setBusinessAccountProfilePhoto", params) return req.Do(api) } @@ -106,8 +106,8 @@ type RemoveBusinessAccountProfilePhotoP struct { IsPublic bool `json:"is_public,omitempty"` } -func (api *Api) RemoveBusinessAccountProfilePhoto(p RemoveBusinessAccountProfilePhotoP) (bool, error) { - req := NewRequest[bool]("removeBusinessAccountProfilePhoto", p) +func (api *Api) RemoveBusinessAccountProfilePhoto(params RemoveBusinessAccountProfilePhotoP) (bool, error) { + req := NewRequest[bool]("removeBusinessAccountProfilePhoto", params) return req.Do(api) } @@ -117,8 +117,8 @@ type SetBusinessAccountGiftSettingsP struct { AcceptedGiftTypes AcceptedGiftTypes `json:"accepted_gift_types"` } -func (api *Api) SetBusinessAccountGiftSettings(p SetBusinessAccountGiftSettingsP) (bool, error) { - req := NewRequest[bool]("setBusinessAccountGiftSettings", p) +func (api *Api) SetBusinessAccountGiftSettings(params SetBusinessAccountGiftSettingsP) (bool, error) { + req := NewRequest[bool]("setBusinessAccountGiftSettings", params) return req.Do(api) } @@ -126,8 +126,8 @@ type GetBusinessAccountStarBalanceP struct { BusinessConnectionID string `json:"business_connection_id"` } -func (api *Api) GetBusinessAccountStarBalance(p GetBusinessAccountStarBalanceP) (StarAmount, error) { - req := NewRequest[StarAmount]("getBusinessAccountGiftSettings", p) +func (api *Api) GetBusinessAccountStarBalance(params GetBusinessAccountStarBalanceP) (StarAmount, error) { + req := NewRequest[StarAmount]("getBusinessAccountGiftSettings", params) return req.Do(api) } @@ -136,8 +136,8 @@ type TransferBusinessAccountStartP struct { StarCount int `json:"star_count"` } -func (api *Api) TransferBusinessAccountStart(p TransferBusinessAccountStartP) (bool, error) { - req := NewRequest[bool]("transferBusinessAccountStart", p) +func (api *Api) TransferBusinessAccountStart(params TransferBusinessAccountStartP) (bool, error) { + req := NewRequest[bool]("transferBusinessAccountStart", params) return req.Do(api) } @@ -155,8 +155,8 @@ type GetBusinessAccountGiftsP struct { Limit int `json:"limit,omitempty"` } -func (api *Api) GetBusinessAccountGifts(p GetBusinessAccountGiftsP) (OwnedGifts, error) { - req := NewRequest[OwnedGifts]("getBusinessAccountGifts", p) +func (api *Api) GetBusinessAccountGifts(params GetBusinessAccountGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getBusinessAccountGifts", params) return req.Do(api) } @@ -165,8 +165,8 @@ type ConvertGiftToStarsP struct { OwnedGiftID string `json:"owned_gift_id"` } -func (api *Api) ConvertGiftToStars(p ConvertGiftToStarsP) (bool, error) { - req := NewRequest[bool]("convertGiftToStars", p) +func (api *Api) ConvertGiftToStars(params ConvertGiftToStarsP) (bool, error) { + req := NewRequest[bool]("convertGiftToStars", params) return req.Do(api) } @@ -177,8 +177,8 @@ type UpgradeGiftP struct { StarCount int `json:"star_count,omitempty"` } -func (api *Api) UpgradeGift(p UpgradeGiftP) (bool, error) { - req := NewRequest[bool]("upgradeGift", p) +func (api *Api) UpgradeGift(params UpgradeGiftP) (bool, error) { + req := NewRequest[bool]("upgradeGift", params) return req.Do(api) } @@ -189,8 +189,8 @@ type TransferGiftP struct { StarCount int `json:"star_count,omitempty"` } -func (api *Api) TransferGift(p TransferGiftP) (bool, error) { - req := NewRequest[bool]("transferGift", p) +func (api *Api) TransferGift(params TransferGiftP) (bool, error) { + req := NewRequest[bool]("transferGift", params) return req.Do(api) } @@ -208,12 +208,12 @@ type PostStoryP struct { ProtectContent bool `json:"protect_content,omitempty"` } -func (api *Api) PostStoryPhoto(p PostStoryP) (Story, error) { - req := NewRequest[Story]("postStory", p) +func (api *Api) PostStoryPhoto(params PostStoryP) (Story, error) { + req := NewRequest[Story]("postStory", params) return req.Do(api) } -func (api *Api) PostStoryVideo(p PostStoryP) (Story, error) { - req := NewRequest[Story]("postStory", p) +func (api *Api) PostStoryVideo(params PostStoryP) (Story, error) { + req := NewRequest[Story]("postStory", params) return req.Do(api) } @@ -226,8 +226,8 @@ type RepostStoryP struct { ProtectContent bool `json:"protect_content,omitempty"` } -func (api *Api) RepostStory(p RepostStoryP) (Story, error) { - req := NewRequest[Story]("repostStory", p) +func (api *Api) RepostStory(params RepostStoryP) (Story, error) { + req := NewRequest[Story]("repostStory", params) return req.Do(api) } @@ -242,8 +242,8 @@ type EditStoryP struct { Areas []StoryArea `json:"areas,omitempty"` } -func (api *Api) EditStory(p EditStoryP) (Story, error) { - req := NewRequest[Story]("editStory", p) +func (api *Api) EditStory(params EditStoryP) (Story, error) { + req := NewRequest[Story]("editStory", params) return req.Do(api) } @@ -252,7 +252,7 @@ type DeleteStoryP struct { StoryID int `json:"story_id"` } -func (api *Api) DeleteStory(p DeleteStoryP) (bool, error) { - req := NewRequest[bool]("deleteStory", p) +func (api *Api) DeleteStory(params DeleteStoryP) (bool, error) { + req := NewRequest[bool]("deleteStory", params) return req.Do(api) } diff --git a/tgapi/chat_methods.go b/tgapi/chat_methods.go index 386c118..f75bee5 100644 --- a/tgapi/chat_methods.go +++ b/tgapi/chat_methods.go @@ -7,8 +7,8 @@ type BanChatMemberP struct { RevokeMessages bool `json:"revoke_messages,omitempty"` } -func (api *Api) BanChatMember(p BanChatMemberP) (bool, error) { - req := NewRequest[bool]("banChatMember", p) +func (api *Api) BanChatMember(params BanChatMemberP) (bool, error) { + req := NewRequest[bool]("banChatMember", params) return req.Do(api) } @@ -18,8 +18,8 @@ type UnbanChatMemberP struct { OnlyIfBanned bool `json:"only_if_banned"` } -func (api *Api) UnbanChatMember(p UnbanChatMemberP) (bool, error) { - req := NewRequest[bool]("unbanChatMember", p) +func (api *Api) UnbanChatMember(params UnbanChatMemberP) (bool, error) { + req := NewRequest[bool]("unbanChatMember", params) return req.Do(api) } @@ -31,8 +31,8 @@ type RestrictChatMemberP struct { UntilDate int `json:"until_date,omitempty"` } -func (api *Api) RestrictChatMember(p RestrictChatMemberP) (bool, error) { - req := NewRequest[bool]("restrictChatMember", p) +func (api *Api) RestrictChatMember(params RestrictChatMemberP) (bool, error) { + req := NewRequest[bool]("restrictChatMember", params) return req.Do(api) } @@ -58,8 +58,8 @@ type PromoteChatMember struct { CanManageDirectMessages bool `json:"can_manage_direct_messages,omitempty"` } -func (api *Api) PromoteChatMember(p PromoteChatMember) (bool, error) { - req := NewRequest[bool]("promoteChatMember", p) +func (api *Api) PromoteChatMember(params PromoteChatMember) (bool, error) { + req := NewRequest[bool]("promoteChatMember", params) return req.Do(api) } @@ -69,8 +69,8 @@ type SetChatAdministratorCustomTitleP struct { CustomTitle string `json:"custom_title"` } -func (api *Api) SetChatAdministratorCustomTitle(p SetChatAdministratorCustomTitleP) (bool, error) { - req := NewRequest[bool]("setChatAdministratorCustomTitle", p) +func (api *Api) SetChatAdministratorCustomTitle(params SetChatAdministratorCustomTitleP) (bool, error) { + req := NewRequest[bool]("setChatAdministratorCustomTitle", params) return req.Do(api) } @@ -79,8 +79,8 @@ type BanChatSenderChatP struct { SenderChatID int `json:"sender_chat_id"` } -func (api *Api) BanChatSenderChat(p BanChatSenderChatP) (bool, error) { - req := NewRequest[bool]("banChatSenderChat", p) +func (api *Api) BanChatSenderChat(params BanChatSenderChatP) (bool, error) { + req := NewRequest[bool]("banChatSenderChat", params) return req.Do(api) } @@ -89,8 +89,8 @@ type UnbanChatSenderChatP struct { SenderChatID int `json:"sender_chat_id"` } -func (api *Api) UnbanChatSenderChat(p BanChatSenderChatP) (bool, error) { - req := NewRequest[bool]("unbanChatSenderChat", p) +func (api *Api) UnbanChatSenderChat(params BanChatSenderChatP) (bool, error) { + req := NewRequest[bool]("unbanChatSenderChat", params) return req.Do(api) } @@ -100,8 +100,8 @@ type SetChatPermissionsP struct { UseIndependentChatPermissions bool `json:"use_independent_chat_permissions,omitempty"` } -func (api *Api) SetChatPermissions(p SetChatPermissionsP) (bool, error) { - req := NewRequest[bool]("setChatPermissions", p) +func (api *Api) SetChatPermissions(params SetChatPermissionsP) (bool, error) { + req := NewRequest[bool]("setChatPermissions", params) return req.Do(api) } @@ -109,8 +109,8 @@ type ExportChatInviteLinkP struct { ChatID int `json:"chat_id"` } -func (api *Api) ExportChatInviteLink(p ExportChatInviteLinkP) (string, error) { - req := NewRequest[string]("exportChatInviteLink", p) +func (api *Api) ExportChatInviteLink(params ExportChatInviteLinkP) (string, error) { + req := NewRequest[string]("exportChatInviteLink", params) return req.Do(api) } @@ -122,8 +122,8 @@ type CreateChatInviteLinkP struct { CreatesJoinRequest int `json:"creates_join_request,omitempty"` } -func (api *Api) CreateChatInviteLink(p CreateChatInviteLinkP) (ChatInviteLink, error) { - req := NewRequest[ChatInviteLink]("createChatInviteLink", p) +func (api *Api) CreateChatInviteLink(params CreateChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("createChatInviteLink", params) return req.Do(api) } @@ -137,8 +137,8 @@ type EditChatInviteLinkP struct { CreatesJoinRequest int `json:"creates_join_request,omitempty"` } -func (api *Api) EditChatInviteLink(p EditChatInviteLinkP) (ChatInviteLink, error) { - req := NewRequest[ChatInviteLink]("editChatInviteLink", p) +func (api *Api) EditChatInviteLink(params EditChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("editChatInviteLink", params) return req.Do(api) } @@ -149,8 +149,8 @@ type CreateChatSubscriptionInviteLinkP struct { SubscriptionPrice int `json:"subscription_price,omitempty"` } -func (api *Api) CreateChatSubscriptionInviteLink(p CreateChatSubscriptionInviteLinkP) (ChatInviteLink, error) { - req := NewRequest[ChatInviteLink]("createChatSubscriptionInviteLink", p) +func (api *Api) CreateChatSubscriptionInviteLink(params CreateChatSubscriptionInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("createChatSubscriptionInviteLink", params) return req.Do(api) } @@ -160,8 +160,8 @@ type EditChatSubscriptionInviteLinkP struct { Name string `json:"name,omitempty"` } -func (api *Api) EditChatSubscriptionInviteLink(p EditChatSubscriptionInviteLinkP) (ChatInviteLink, error) { - req := NewRequest[ChatInviteLink]("editChatSubscriptionInviteLink", p) +func (api *Api) EditChatSubscriptionInviteLink(params EditChatSubscriptionInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("editChatSubscriptionInviteLink", params) return req.Do(api) } @@ -170,8 +170,8 @@ type RevokeChatInviteLinkP struct { InviteLink string `json:"invite_link"` } -func (api *Api) RevokeChatInviteLink(p RevokeChatInviteLinkP) (ChatInviteLink, error) { - req := NewRequest[ChatInviteLink]("revokeChatInviteLink", p) +func (api *Api) RevokeChatInviteLink(params RevokeChatInviteLinkP) (ChatInviteLink, error) { + req := NewRequest[ChatInviteLink]("revokeChatInviteLink", params) return req.Do(api) } @@ -180,8 +180,8 @@ type ApproveChatJoinRequestP struct { UserID int `json:"user_id"` } -func (api *Api) ApproveChatJoinRequest(p ApproveChatJoinRequestP) (bool, error) { - req := NewRequest[bool]("approveChatJoinRequest", p) +func (api *Api) ApproveChatJoinRequest(params ApproveChatJoinRequestP) (bool, error) { + req := NewRequest[bool]("approveChatJoinRequest", params) return req.Do(api) } @@ -190,8 +190,8 @@ type DeclineChatJoinRequestP struct { UserID int `json:"user_id"` } -func (api *Api) DeclineChatJoinRequest(p DeclineChatJoinRequestP) (bool, error) { - req := NewRequest[bool]("declineChatJoinRequest", p) +func (api *Api) DeclineChatJoinRequest(params DeclineChatJoinRequestP) (bool, error) { + req := NewRequest[bool]("declineChatJoinRequest", params) return req.Do(api) } @@ -204,8 +204,8 @@ type DeleteChatPhotoP struct { ChatID int `json:"chat_id"` } -func (api *Api) DeleteChatPhoto(p DeleteChatPhotoP) (bool, error) { - req := NewRequest[bool]("deleteChatPhoto", p) +func (api *Api) DeleteChatPhoto(params DeleteChatPhotoP) (bool, error) { + req := NewRequest[bool]("deleteChatPhoto", params) return req.Do(api) } @@ -214,8 +214,8 @@ type SetChatTitleP struct { Title string `json:"title"` } -func (api *Api) SetChatTitle(p SetChatTitleP) (bool, error) { - req := NewRequest[bool]("setChatTitle", p) +func (api *Api) SetChatTitle(params SetChatTitleP) (bool, error) { + req := NewRequest[bool]("setChatTitle", params) return req.Do(api) } @@ -224,8 +224,8 @@ type SetChatDescriptionP struct { Description string `json:"description"` } -func (api *Api) SetChatDescription(p SetChatDescriptionP) (bool, error) { - req := NewRequest[bool]("setChatDescription", p) +func (api *Api) SetChatDescription(params SetChatDescriptionP) (bool, error) { + req := NewRequest[bool]("setChatDescription", params) return req.Do(api) } @@ -236,8 +236,8 @@ type PinChatMessageP struct { DisableNotification bool `json:"disable_notification,omitempty"` } -func (api *Api) PinChatMessage(p PinChatMessageP) (bool, error) { - req := NewRequest[bool]("pinChatMessage", p) +func (api *Api) PinChatMessage(params PinChatMessageP) (bool, error) { + req := NewRequest[bool]("pinChatMessage", params) return req.Do(api) } @@ -247,8 +247,8 @@ type UnpinChatMessageP struct { MessageID int `json:"message_id"` } -func (api *Api) UnpinChatMessage(p UnpinChatMessageP) (bool, error) { - req := NewRequest[bool]("unpinChatMessage", p) +func (api *Api) UnpinChatMessage(params UnpinChatMessageP) (bool, error) { + req := NewRequest[bool]("unpinChatMessage", params) return req.Do(api) } @@ -256,8 +256,8 @@ type UnpinAllChatMessagesP struct { ChatID int `json:"chat_id"` } -func (api *Api) UnpinAllChatMessages(p UnpinAllChatMessagesP) (bool, error) { - req := NewRequest[bool]("unpinAllChatMessages", p) +func (api *Api) UnpinAllChatMessages(params UnpinAllChatMessagesP) (bool, error) { + req := NewRequest[bool]("unpinAllChatMessages", params) return req.Do(api) } @@ -265,8 +265,8 @@ type LeaveChatP struct { ChatID int `json:"chat_id"` } -func (api *Api) LeaveChat(p LeaveChatP) (bool, error) { - req := NewRequest[bool]("leaveChatP", p) +func (api *Api) LeaveChat(params LeaveChatP) (bool, error) { + req := NewRequest[bool]("leaveChatP", params) return req.Do(api) } @@ -274,8 +274,8 @@ type GetChatP struct { ChatID int `json:"chat_id"` } -func (api *Api) GetChatP(p GetChatP) (ChatFullInfo, error) { - req := NewRequest[ChatFullInfo]("getChatP", p) +func (api *Api) GetChatP(params GetChatP) (ChatFullInfo, error) { + req := NewRequest[ChatFullInfo]("getChatP", params) return req.Do(api) } @@ -283,8 +283,8 @@ type GetChatAdministratorsP struct { ChatID int `json:"chat_id"` } -func (api *Api) GetChatAdministrators(p GetChatAdministratorsP) ([]ChatMember, error) { - req := NewRequest[[]ChatMember]("getChatAdministrators", p) +func (api *Api) GetChatAdministrators(params GetChatAdministratorsP) ([]ChatMember, error) { + req := NewRequest[[]ChatMember]("getChatAdministrators", params) return req.Do(api) } @@ -292,8 +292,8 @@ type GetChatMembersCountP struct { ChatID int `json:"chat_id"` } -func (api *Api) GetChatMemberCount(p GetChatMembersCountP) (int, error) { - req := NewRequest[int]("getChatMemberCount", p) +func (api *Api) GetChatMemberCount(params GetChatMembersCountP) (int, error) { + req := NewRequest[int]("getChatMemberCount", params) return req.Do(api) } @@ -302,8 +302,8 @@ type GetChatMemberP struct { UserID int `json:"user_id"` } -func (api *Api) GetChatMember(p GetChatMemberP) (ChatMember, error) { - req := NewRequest[ChatMember]("getChatMember", p) +func (api *Api) GetChatMember(params GetChatMemberP) (ChatMember, error) { + req := NewRequest[ChatMember]("getChatMember", params) return req.Do(api) } @@ -312,8 +312,8 @@ type SetChatStickerSetP struct { StickerSetName string `json:"sticker_set_name"` } -func (api *Api) SetChatStickerSet(p SetChatStickerSetP) (bool, error) { - req := NewRequest[bool]("setChatStickerSet", p) +func (api *Api) SetChatStickerSet(params SetChatStickerSetP) (bool, error) { + req := NewRequest[bool]("setChatStickerSet", params) return req.Do(api) } @@ -321,8 +321,8 @@ type DeleteChatStickerSetP struct { ChatID int `json:"chat_id"` } -func (api *Api) DeleteChatStickerSet(p DeleteChatStickerSetP) (bool, error) { - req := NewRequest[bool]("deleteChatStickerSet", p) +func (api *Api) DeleteChatStickerSet(params DeleteChatStickerSetP) (bool, error) { + req := NewRequest[bool]("deleteChatStickerSet", params) return req.Do(api) } @@ -331,8 +331,8 @@ type GetUserChatBoostsP struct { UserID int `json:"user_id"` } -func (api *Api) GetUserChatBoosts(p GetUserChatBoostsP) (UserChatBoosts, error) { - req := NewRequest[UserChatBoosts]("getUserChatBoosts", p) +func (api *Api) GetUserChatBoosts(params GetUserChatBoostsP) (UserChatBoosts, error) { + req := NewRequest[UserChatBoosts]("getUserChatBoosts", params) return req.Do(api) } @@ -350,7 +350,7 @@ type GetChatGiftsP struct { Limit int `json:"limit,omitempty"` } -func (api *Api) GetChatGifts(p GetChatGiftsP) (OwnedGifts, error) { - req := NewRequest[OwnedGifts]("getChatGifts", p) +func (api *Api) GetChatGifts(params GetChatGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getChatGifts", params) return req.Do(api) } diff --git a/tgapi/forum_methods.go b/tgapi/forum_methods.go index 48e31e2..df2da3a 100644 --- a/tgapi/forum_methods.go +++ b/tgapi/forum_methods.go @@ -17,8 +17,8 @@ type CreateForumTopicP struct { IconCustomEmojiID string `json:"icon_custom_emoji_id"` } -func (api *Api) CreateForumTopic(p CreateForumTopicP) (ForumTopic, error) { - req := NewRequest[ForumTopic]("createForumTopic", p) +func (api *Api) CreateForumTopic(params CreateForumTopicP) (ForumTopic, error) { + req := NewRequest[ForumTopic]("createForumTopic", params) return req.Do(api) } @@ -28,25 +28,25 @@ type EditForumTopicP struct { IconCustomEmojiID string `json:"icon_custom_emoji_id"` } -func (api *Api) EditForumTopic(p EditForumTopicP) (bool, error) { - req := NewRequest[bool]("editForumTopic", p) +func (api *Api) EditForumTopic(params EditForumTopicP) (bool, error) { + req := NewRequest[bool]("editForumTopic", params) return req.Do(api) } -func (api *Api) CloseForumTopic(p BaseForumTopicP) (bool, error) { - req := NewRequest[bool]("closeForumTopic", p) +func (api *Api) CloseForumTopic(params BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("closeForumTopic", params) return req.Do(api) } -func (api *Api) ReopenForumTopic(p BaseForumTopicP) (bool, error) { - req := NewRequest[bool]("reopenForumTopic", p) +func (api *Api) ReopenForumTopic(params BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("reopenForumTopic", params) return req.Do(api) } -func (api *Api) DeleteForumTopic(p BaseForumTopicP) (bool, error) { - req := NewRequest[bool]("deleteForumTopic", p) +func (api *Api) DeleteForumTopic(params BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("deleteForumTopic", params) return req.Do(api) } -func (api *Api) UnpinAllForumTopicMessages(p BaseForumTopicP) (bool, error) { - req := NewRequest[bool]("unpinAllForumTopicMessages", p) +func (api *Api) UnpinAllForumTopicMessages(params BaseForumTopicP) (bool, error) { + req := NewRequest[bool]("unpinAllForumTopicMessages", params) return req.Do(api) } @@ -59,28 +59,28 @@ type EditGeneralForumTopicP struct { Name string `json:"name"` } -func (api *Api) EditGeneralForumTopic(p EditGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("editGeneralForumTopic", p) +func (api *Api) EditGeneralForumTopic(params EditGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("editGeneralForumTopic", params) return req.Do(api) } -func (api *Api) CloseGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("closeGeneralForumTopic", p) +func (api *Api) CloseGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("closeGeneralForumTopic", params) return req.Do(api) } -func (api *Api) ReopenGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("reopenGeneralForumTopic", p) +func (api *Api) ReopenGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("reopenGeneralForumTopic", params) return req.Do(api) } -func (api *Api) HideGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("hideGeneralForumTopic", p) +func (api *Api) HideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("hideGeneralForumTopic", params) return req.Do(api) } -func (api *Api) UnhideGeneralForumTopic(p BaseGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("unhideGeneralForumTopic", p) +func (api *Api) UnhideGeneralForumTopic(params BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("unhideGeneralForumTopic", params) return req.Do(api) } -func (api *Api) UnpinAllGeneralForumTopicMessages(p BaseGeneralForumTopicP) (bool, error) { - req := NewRequest[bool]("unpinAllGeneralForumTopicMessages", p) +func (api *Api) UnpinAllGeneralForumTopicMessages(params BaseGeneralForumTopicP) (bool, error) { + req := NewRequest[bool]("unpinAllGeneralForumTopicMessages", params) return req.Do(api) } diff --git a/tgapi/messages_methods.go b/tgapi/messages_methods.go index ba8a1ff..09fc098 100644 --- a/tgapi/messages_methods.go +++ b/tgapi/messages_methods.go @@ -20,8 +20,8 @@ type SendMessageP struct { ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` } -func (api *Api) SendMessage(params *SendMessageP) (Message, error) { - req := NewRequest[Message, SendMessageP]("sendMessage", *params) +func (api *Api) SendMessage(params SendMessageP) (Message, error) { + req := NewRequest[Message, SendMessageP]("sendMessage", params) return req.Do(api) } @@ -315,9 +315,18 @@ type EditMessageTextP struct { ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` } -func (api *Api) EditMessageText(params *EditMessageTextP) (Message, error) { +// EditMessageText If inline message, first return will be zero-valued, and second will boolean +// Otherwise, first return will be Message, and second false +func (api *Api) EditMessageText(params EditMessageTextP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("editMessageText", params) + res, err := req.Do(api) + return zero, res, err + } req := NewRequest[Message]("editMessageText", params) - return req.Do(api) + res, err := req.Do(api) + return res, false, err } type EditMessageCaptionP struct { @@ -330,8 +339,158 @@ type EditMessageCaptionP struct { ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` } -func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (Message, error) { +// EditMessageCaption If inline message, first return will be zero-valued, and second will boolean +// Otherwise, first return will be Message, and second false +func (api *Api) EditMessageCaption(params EditMessageCaptionP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("editMessageCaption", params) + res, err := req.Do(api) + return zero, res, err + } req := NewRequest[Message]("editMessageCaption", params) + res, err := req.Do(api) + return res, false, err +} + +type EditMessageMediaP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Message InputMedia `json:"message"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// EditMessageMedia If inline message, first return will be zero-valued, and second will boolean +// Otherwise, first return will be Message, and second false +func (api *Api) EditMessageMedia(params EditMessageMediaP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("editMessageMedia", params) + res, err := req.Do(api) + return zero, res, err + } + req := NewRequest[Message]("editMessageMedia", params) + res, err := req.Do(api) + return res, false, err +} + +type EditMessageLiveLocationP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + LivePeriod int `json:"live_period,omitempty"` + HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` + Heading int `json:"heading,omitempty"` + ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// EditMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean +// Otherwise, first return will be Message, and second false +func (api *Api) EditMessageLiveLocation(params EditMessageLiveLocationP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("editMessageLiveLocation", params) + res, err := req.Do(api) + return zero, res, err + } + req := NewRequest[Message]("editMessageLiveLocation", params) + res, err := req.Do(api) + return res, false, err +} + +type StopMessageLiveLocationP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// StopMessageLiveLocation If inline message, first return will be zero-valued, and second will boolean +// Otherwise, first return will be Message, and second false +func (api *Api) StopMessageLiveLocation(params StopMessageLiveLocationP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("stopMessageLiveLocation", params) + res, err := req.Do(api) + return zero, res, err + } + req := NewRequest[Message]("stopMessageLiveLocation", params) + res, err := req.Do(api) + return res, false, err +} + +type EditMessageChecklistP struct { + BusinessConnectionID string `json:"business_connection_id"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + Checklist InputChecklist `json:"checklist"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) EditMessageChecklist(params EditMessageChecklistP) (Message, error) { + req := NewRequest[Message]("editMessageChecklist", params) + return req.Do(api) +} + +type EditMessageReplyMarkupP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) EditMessageReplyMarkup(params EditMessageReplyMarkupP) (Message, bool, error) { + var zero Message + if params.InlineMessageID != "" { + req := NewRequest[bool]("editMessageReplyMarkup", params) + res, err := req.Do(api) + return zero, res, err + } + req := NewRequest[Message]("editMessageReplyMarkup", params) + res, err := req.Do(api) + return res, false, err +} + +type StopPollP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + InlineMessageID string `json:"inline_message_id,omitempty"` +} + +func (api *Api) StopPoll(params StopPollP) (Poll, error) { + req := NewRequest[Poll]("stopPoll", params) + return req.Do(api) +} + +type ApproveSuggestedPostP struct { + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + SendDate int `json:"send_date,omitempty"` +} + +func (api *Api) ApproveSuggestedPost(params ApproveSuggestedPostP) (bool, error) { + req := NewRequest[bool]("approveSuggestedPost", params) + return req.Do(api) +} + +type DeclineSuggestedPostP struct { + ChatID int `json:"chat_id"` + MessageID int `json:"message_id"` + Comment string `json:"comment,omitempty"` +} + +func (api *Api) DeclineSuggestedPost(params DeclineSuggestedPostP) (bool, error) { + req := NewRequest[bool]("declineSuggestedPost", params) return req.Do(api) } @@ -340,11 +499,21 @@ type DeleteMessageP struct { MessageID int `json:"message_id"` } -func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) { +func (api *Api) DeleteMessage(params DeleteMessageP) (bool, error) { req := NewRequest[bool]("deleteMessage", params) return req.Do(api) } +type DeleteMessagesP struct { + ChatID int `json:"chat_id"` + MessageIDs []int `json:"message_ids"` +} + +func (api *Api) DeleteMessages(params DeleteMessagesP) (bool, error) { + req := NewRequest[bool]("deleteMessages", params) + return req.Do(api) +} + type AnswerCallbackQueryP struct { CallbackQueryID string `json:"callback_query_id"` Text string `json:"text,omitempty"` @@ -353,7 +522,7 @@ type AnswerCallbackQueryP struct { CacheTime int `json:"cache_time,omitempty"` } -func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { +func (api *Api) AnswerCallbackQuery(params AnswerCallbackQueryP) (bool, error) { req := NewRequest[bool]("answerCallbackQuery", params) return req.Do(api) } diff --git a/tgapi/methods.go b/tgapi/methods.go index c75e2e8..9c20e88 100644 --- a/tgapi/methods.go +++ b/tgapi/methods.go @@ -31,6 +31,10 @@ func (api *Api) Close() (bool, error) { req := NewRequest[bool, EmptyParams]("close", NoParams) return req.Do(api) } +func (api *Api) GetUpdates(params UpdateParams) ([]Update, error) { + req := NewRequest[[]Update]("getUpdates", params) + return req.Do(api) +} type GetFileP struct { FileId string `json:"file_id"` diff --git a/tgapi/stickers_methods.go b/tgapi/stickers_methods.go index f86977d..99feeb8 100644 --- a/tgapi/stickers_methods.go +++ b/tgapi/stickers_methods.go @@ -14,8 +14,8 @@ type SendStickerP struct { MessageEffectID string `json:"message_effect_id,omitempty"` } -func (api *Api) SendSticker(p SendStickerP) (Message, error) { - req := NewRequest[Message]("sendSticker", p) +func (api *Api) SendSticker(params SendStickerP) (Message, error) { + req := NewRequest[Message]("sendSticker", params) return req.Do(api) } @@ -23,8 +23,8 @@ type GetStickerSetP struct { Name string `json:"name"` } -func (api *Api) GetStickerSet(p GetStickerSetP) (StickerSet, error) { - req := NewRequest[StickerSet]("getStickerSet", p) +func (api *Api) GetStickerSet(params GetStickerSetP) (StickerSet, error) { + req := NewRequest[StickerSet]("getStickerSet", params) return req.Do(api) } @@ -32,8 +32,8 @@ type GetCustomEmojiStickersP struct { CustomEmojiIDs []string `json:"custom_emoji_ids"` } -func (api *Api) GetCustomEmojiStickers(p GetCustomEmojiStickersP) ([]Sticker, error) { - req := NewRequest[[]Sticker]("getCustomEmojiStickers", p) +func (api *Api) GetCustomEmojiStickers(params GetCustomEmojiStickersP) ([]Sticker, error) { + req := NewRequest[[]Sticker]("getCustomEmojiStickers", params) return req.Do(api) } @@ -47,8 +47,8 @@ type CreateNewStickerSetP struct { NeedsRepainting bool `json:"needs_repainting,omitempty"` } -func (api *Api) CreateNewStickerSet(p CreateNewStickerSetP) (bool, error) { - req := NewRequest[bool]("createNewStickerSet", p) +func (api *Api) CreateNewStickerSet(params CreateNewStickerSetP) (bool, error) { + req := NewRequest[bool]("createNewStickerSet", params) return req.Do(api) } @@ -58,8 +58,8 @@ type AddStickerToSetP struct { Sticker InputSticker `json:"sticker"` } -func (api *Api) AddStickerToSet(p AddStickerToSetP) (bool, error) { - req := NewRequest[bool]("addStickerToSet", p) +func (api *Api) AddStickerToSet(params AddStickerToSetP) (bool, error) { + req := NewRequest[bool]("addStickerToSet", params) return req.Do(api) } @@ -68,8 +68,8 @@ type SetStickerPositionInSetP struct { Position int `json:"position"` } -func (api *Api) SetStickerPosition(p SetStickerPositionInSetP) (bool, error) { - req := NewRequest[bool]("setStickerPosition", p) +func (api *Api) SetStickerPosition(params SetStickerPositionInSetP) (bool, error) { + req := NewRequest[bool]("setStickerPosition", params) return req.Do(api) } @@ -77,8 +77,8 @@ type DeleteStickerFromSetP struct { Sticker string `json:"sticker"` } -func (api *Api) DeleteStickerFromSet(p DeleteStickerFromSetP) (bool, error) { - req := NewRequest[bool]("deleteStickerFromSet", p) +func (api *Api) DeleteStickerFromSet(params DeleteStickerFromSetP) (bool, error) { + req := NewRequest[bool]("deleteStickerFromSet", params) return req.Do(api) } @@ -89,8 +89,8 @@ type ReplaceStickerInSetP struct { Sticker InputSticker `json:"sticker"` } -func (api *Api) ReplaceStickerInSet(p ReplaceStickerInSetP) (bool, error) { - req := NewRequest[bool]("replaceStickerInSet", p) +func (api *Api) ReplaceStickerInSet(params ReplaceStickerInSetP) (bool, error) { + req := NewRequest[bool]("replaceStickerInSet", params) return req.Do(api) } @@ -99,8 +99,8 @@ type SetStickerEmojiListP struct { EmojiList []string `json:"emoji_list"` } -func (api *Api) SetStickerEmojiList(p SetStickerEmojiListP) (bool, error) { - req := NewRequest[bool]("setStickerEmojiList", p) +func (api *Api) SetStickerEmojiList(params SetStickerEmojiListP) (bool, error) { + req := NewRequest[bool]("setStickerEmojiList", params) return req.Do(api) } @@ -109,8 +109,8 @@ type SetStickerKeywordsP struct { Keywords []string `json:"keywords"` } -func (api *Api) SetStickerKeywords(p SetStickerKeywordsP) (bool, error) { - req := NewRequest[bool]("setStickerKeywords", p) +func (api *Api) SetStickerKeywords(params SetStickerKeywordsP) (bool, error) { + req := NewRequest[bool]("setStickerKeywords", params) return req.Do(api) } @@ -119,8 +119,8 @@ type SetStickerMaskPositionP struct { MaskPosition *MaskPosition `json:"mask_position,omitempty"` } -func (api *Api) SetStickerMaskPosition(p SetStickerMaskPositionP) (bool, error) { - req := NewRequest[bool]("setStickerMaskPosition", p) +func (api *Api) SetStickerMaskPosition(params SetStickerMaskPositionP) (bool, error) { + req := NewRequest[bool]("setStickerMaskPosition", params) return req.Do(api) } @@ -129,8 +129,8 @@ type SetStickerSetTitleP struct { Title string `json:"title"` } -func (api *Api) SetStickerSetTitle(p SetStickerSetTitleP) (bool, error) { - req := NewRequest[bool]("setStickerSetTitle", p) +func (api *Api) SetStickerSetTitle(params SetStickerSetTitleP) (bool, error) { + req := NewRequest[bool]("setStickerSetTitle", params) return req.Do(api) } @@ -141,8 +141,8 @@ type SetStickerSetThumbnailP struct { Format InputStickerFormat `json:"format"` } -func (api *Api) SetStickerSetThumbnail(p SetStickerSetThumbnailP) (bool, error) { - req := NewRequest[bool]("setStickerSetThumbnail", p) +func (api *Api) SetStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) { + req := NewRequest[bool]("setStickerSetThumbnail", params) return req.Do(api) } @@ -151,8 +151,8 @@ type SetCustomEmojiStickerSetThumbnailP struct { CustomEmojiID string `json:"custom_emoji_id,omitempty"` } -func (api *Api) SetCustomEmojiStickerSetThumbnail(p SetStickerSetThumbnailP) (bool, error) { - req := NewRequest[bool]("setCustomEmojiStickerSetThumbnail", p) +func (api *Api) SetCustomEmojiStickerSetThumbnail(params SetStickerSetThumbnailP) (bool, error) { + req := NewRequest[bool]("setCustomEmojiStickerSetThumbnail", params) return req.Do(api) } @@ -160,7 +160,7 @@ type DeleteStickerSetP struct { Name string `json:"name"` } -func (api *Api) DeleteStickerSet(p DeleteStickerSetP) (bool, error) { - req := NewRequest[bool]("deleteStickerSet", p) +func (api *Api) DeleteStickerSet(params DeleteStickerSetP) (bool, error) { + req := NewRequest[bool]("deleteStickerSet", params) return req.Do(api) } diff --git a/tgapi/uploader.go b/tgapi/uploader.go index 33b9b52..7062503 100644 --- a/tgapi/uploader.go +++ b/tgapi/uploader.go @@ -2,6 +2,7 @@ package tgapi import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -36,116 +37,307 @@ const ( UploaderDocumentType UploaderFileType = "document" UploaderVoiceType UploaderFileType = "voice" UploaderVideoNoteType UploaderFileType = "video_note" + UploaderThumbnailType UploaderFileType = "thumbnail" ) type UploaderFile struct { filename string data []byte - t UploaderFileType + field UploaderFileType } func NewUploaderFile(name string, data []byte) UploaderFile { t := uploaderTypeByExt(name) - return UploaderFile{filename: name, data: data, t: t} + return UploaderFile{filename: name, data: data, field: t} } -// SetType used when auto-detect failed. I.e. you sending a voice message, but it detects as audio +// SetType used when auto-detect failed. I.e. you sending a voice message, but it detects as audio, or if you send audio with thumbnail func (f UploaderFile) SetType(t UploaderFileType) UploaderFile { - f.t = t + f.field = t return f } type UploaderRequest[R, P any] struct { method string - file UploaderFile + files []UploaderFile params P } -func NewUploaderRequest[R, P any](method string, file UploaderFile, params P) UploaderRequest[R, P] { - return UploaderRequest[R, P]{method, file, params} +func NewUploaderRequest[R, P any](method string, params P, files ...UploaderFile) UploaderRequest[R, P] { + return UploaderRequest[R, P]{method, files, params} } - -func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) { +func (u UploaderRequest[R, P]) DoWithContext(ctx context.Context, up *Uploader) (R, error) { + var zero R url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method) buf := bytes.NewBuffer(nil) w := multipart.NewWriter(buf) - fw, err := w.CreateFormFile(string(u.file.t), u.file.filename) - if err != nil { - w.Close() - return nil, err + for _, file := range u.files { + fw, err := w.CreateFormFile(string(file.field), file.filename) + if err != nil { + w.Close() + return zero, err + } + _, err = fw.Write(file.data) + if err != nil { + w.Close() + return zero, err + } } - _, err = fw.Write(u.file.data) + + err := utils.Encode(w, u.params) if err != nil { w.Close() - return nil, err - } - err = utils.Encode(w, u.params) - if err != nil { - w.Close() - return nil, err + return zero, err } err = w.Close() if err != nil { - return nil, err + return zero, err } - req, err := http.NewRequest("POST", url, buf) + req, err := http.NewRequestWithContext(ctx, "POST", url, buf) if err != nil { - return nil, err + return zero, err } req.Header.Set("Content-Type", w.FormDataContentType()) + req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString)) + up.logger.Debugln("UPLOADER REQ", u.method) - res, err := http.DefaultClient.Do(req) + res, err := up.api.client.Do(req) if err != nil { - return nil, err + return zero, err } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { - return nil, err + return zero, err } up.logger.Debugln("UPLOADER RES", u.method, string(body)) if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body)) + return zero, fmt.Errorf("[%d] %s", res.StatusCode, string(body)) } - response := new(ApiResponse[*R]) - err = json.Unmarshal(body, response) + var response ApiResponse[R] + err = json.Unmarshal(body, &response) if err != nil { - return nil, err + return zero, err } if !response.Ok { - return nil, fmt.Errorf("[%d] %s", response.ErrorCode, response.Description) + return zero, fmt.Errorf("[%d] %s", response.ErrorCode, response.Description) } return response.Result, nil } - -type UploadPhotoP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +func (u UploaderRequest[R, P]) Do(up *Uploader) (R, error) { + ctx := context.Background() + return u.DoWithContext(ctx, up) } -func (u *Uploader) UploadPhoto(file UploaderFile, params UploadPhotoP) (*Message, error) { - req := NewUploaderRequest[Message]("sendPhoto", file, params) +type UploadPhotoP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadPhoto(params UploadPhotoP, file UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendPhoto", params, file) + return req.Do(u) +} + +type UploadAudioP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + Duration int `json:"duration,omitempty"` + Performer string `json:"performer,omitempty"` + Title string `json:"title,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadAudio(params UploadAudioP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendAudio", params, files...) + return req.Do(u) +} + +type UploadDocumentP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + DisableContentTypeDetection bool `json:"disable_content_type_detection,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadDocument(params UploadDocumentP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendDocument", params, files...) + return req.Do(u) +} + +type UploadVideoP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Duration int `json:"duration,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + + StartTimestamp int64 `json:"start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + SupportsStreaming bool `json:"supports_streaming,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadVideo(params UploadVideoP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendVideo", params, files...) + return req.Do(u) +} + +type UploadAnimationP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Duration int `json:"duration,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadAnimation(params UploadAnimationP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendAnimation", params, files...) + return req.Do(u) +} + +type UploadVoiceP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Duration int `json:"duration,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadVoice(params UploadVoiceP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendVoice", params, files...) + return req.Do(u) +} + +type UploadVideoNoteP struct { + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Duration int `json:"duration,omitempty"` + Length int `json:"length,omitempty"` + + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"` +} + +func (u *Uploader) UploadVideoNote(params UploadVideoNoteP, files ...UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendVideoNote", params, files...) return req.Do(u) } // setChatPhoto https://core.telegram.org/bots/api#setchatphoto type UploadChatPhotoP struct { + ChatID int `json:"chat_id"` +} + +func (u *Uploader) UploadChatPhoto(params UploadChatPhotoP, photo UploaderFile) (Message, error) { + req := NewUploaderRequest[Message]("sendChatPhoto", params, photo) + return req.Do(u) } func uploaderTypeByExt(filename string) UploaderFileType { diff --git a/tgapi/users_methods.go b/tgapi/users_methods.go index 24cb024..d254140 100644 --- a/tgapi/users_methods.go +++ b/tgapi/users_methods.go @@ -6,8 +6,8 @@ type GetUserProfilePhotosP struct { Limit int `json:"limit,omitempty"` } -func (api *Api) GetUserProfilePhotos(p GetUserProfilePhotosP) (UserProfilePhotos, error) { - req := NewRequest[UserProfilePhotos]("getUserProfilePhotos", p) +func (api *Api) GetUserProfilePhotos(params GetUserProfilePhotosP) (UserProfilePhotos, error) { + req := NewRequest[UserProfilePhotos]("getUserProfilePhotos", params) return req.Do(api) } @@ -17,8 +17,8 @@ type GetUserProfileAudiosP struct { Limit int `json:"limit,omitempty"` } -func (api *Api) GetUserProfileAudios(p GetUserProfileAudiosP) (UserProfileAudios, error) { - req := NewRequest[UserProfileAudios]("getUserProfileAudios", p) +func (api *Api) GetUserProfileAudios(params GetUserProfileAudiosP) (UserProfileAudios, error) { + req := NewRequest[UserProfileAudios]("getUserProfileAudios", params) return req.Do(api) } @@ -28,8 +28,8 @@ type SetUserEmojiStatusP struct { ExpirationDate int `json:"emoji_status_expiration_date,omitempty"` } -func (api *Api) SetUserEmojiStatus(p SetUserEmojiStatusP) (bool, error) { - req := NewRequest[bool]("setUserEmojiStatus", p) +func (api *Api) SetUserEmojiStatus(params SetUserEmojiStatusP) (bool, error) { + req := NewRequest[bool]("setUserEmojiStatus", params) return req.Do(api) } @@ -45,7 +45,7 @@ type GetUserGiftsP struct { Limit int `json:"limit,omitempty"` } -func (api *Api) GetUserGifts(p GetUserGiftsP) (OwnedGifts, error) { - req := NewRequest[OwnedGifts]("getUserGifts", p) +func (api *Api) GetUserGifts(params GetUserGiftsP) (OwnedGifts, error) { + req := NewRequest[OwnedGifts]("getUserGifts", params) return req.Do(api) } -- 2.53.0 From ece131c14a21bcb51bf4c82a87a5e27a18d971d6 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Thu, 12 Feb 2026 11:17:23 +0300 Subject: [PATCH 15/16] refactor --- bot.go | 23 +++-------------------- handler.go | 14 +++++++++++++- plugins.go | 52 +++++++++++++++++----------------------------------- runners.go | 1 + 4 files changed, 34 insertions(+), 56 deletions(-) diff --git a/bot.go b/bot.go index f17db42..930c61c 100644 --- a/bot.go +++ b/bot.go @@ -233,7 +233,6 @@ func (b *Bot) Run() { return } - b.logger.Infoln("Executing runners...") b.ExecRunners() b.logger.Infoln("Bot running. Press CTRL+C to exit.") @@ -247,33 +246,17 @@ func (b *Bot) Run() { }() for { - queue := b.updateQueue - if queue.IsEmpty() { + if b.updateQueue.IsEmpty() { time.Sleep(time.Millisecond * 25) continue } - u := queue.Dequeue() + u := b.updateQueue.Dequeue() if u == nil { b.logger.Errorln("update is nil") continue } - ctx := &MsgContext{Bot: b, Update: u, Api: b.api} - for _, middleware := range b.middlewares { - middleware.Execute(ctx, b.dbContext) - } - - for _, plugin := range b.plugins { - if plugin.UpdateListener != nil { - (*plugin.UpdateListener)(ctx, b.dbContext) - } - } - - if u.CallbackQuery != nil { - b.handleCallback(u, ctx) - } else { - b.handleMessage(u, ctx) - } + b.handle(u) } } diff --git a/handler.go b/handler.go index 487843d..030fe3c 100644 --- a/handler.go +++ b/handler.go @@ -5,6 +5,19 @@ import ( "strings" ) +func (b *Bot) handle(u *Update) { + ctx := &MsgContext{Bot: b, Update: u, Api: b.api} + for _, middleware := range b.middlewares { + middleware.Execute(ctx, b.dbContext) + } + + if u.CallbackQuery != nil { + b.handleCallback(u, ctx) + } else { + b.handleMessage(u, ctx) + } +} + func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { if update.Message == nil { return @@ -30,7 +43,6 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { text = strings.TrimSpace(text[len(prefix):]) for _, plugin := range b.plugins { - // Check every command for cmd := range plugin.Commands { if !strings.HasPrefix(text, cmd) { continue diff --git a/plugins.go b/plugins.go index 945bbc3..d6768f9 100644 --- a/plugins.go +++ b/plugins.go @@ -9,49 +9,42 @@ import ( type CommandExecutor func(ctx *MsgContext, dbContext *DatabaseContext) type PluginBuilder struct { - name string - commands map[string]*CommandExecutor - payloads map[string]*CommandExecutor - updateListener *CommandExecutor - middlewares extypes.Slice[*PluginMiddleware] + name string + commands map[string]CommandExecutor + payloads map[string]CommandExecutor + middlewares extypes.Slice[*PluginMiddleware] } type Plugin struct { - Name string - Commands map[string]*CommandExecutor - Payloads map[string]*CommandExecutor - UpdateListener *CommandExecutor - Middlewares extypes.Slice[*PluginMiddleware] + Name string + Commands map[string]CommandExecutor + Payloads map[string]CommandExecutor + Middlewares extypes.Slice[*PluginMiddleware] } func NewPlugin(name string) *PluginBuilder { return &PluginBuilder{ name: name, - commands: make(map[string]*CommandExecutor), - payloads: make(map[string]*CommandExecutor), + commands: make(map[string]CommandExecutor), + payloads: make(map[string]CommandExecutor), } } func (p *PluginBuilder) Command(f CommandExecutor, cmd ...string) *PluginBuilder { for _, c := range cmd { - p.commands[c] = &f + p.commands[c] = f } return p } func (p *PluginBuilder) Payload(f CommandExecutor, payloads ...string) *PluginBuilder { for _, payload := range payloads { - p.payloads[payload] = &f + p.payloads[payload] = f } return p } -func (p *PluginBuilder) UpdateListener(listener CommandExecutor) *PluginBuilder { - p.updateListener = &listener - return p -} - -func (p *PluginBuilder) Middleware(middleware *PluginMiddleware) *PluginBuilder { +func (p *PluginBuilder) AddMiddleware(middleware *PluginMiddleware) *PluginBuilder { p.middlewares = p.middlewares.Push(middleware) return p } @@ -61,20 +54,17 @@ func (p *PluginBuilder) Build() Plugin { log.Printf("no command or payloads for %s", p.name) } return Plugin{ - Name: p.name, - Commands: p.commands, - Payloads: p.payloads, - UpdateListener: p.updateListener, - Middlewares: p.middlewares, + p.name, p.commands, + p.payloads, p.middlewares, } } func (p *Plugin) Execute(cmd string, ctx *MsgContext, dbContext *DatabaseContext) { - (*p.Commands[cmd])(ctx, dbContext) + (p.Commands[cmd])(ctx, dbContext) } func (p *Plugin) ExecutePayload(payload string, ctx *MsgContext, dbContext *DatabaseContext) { - (*p.Payloads[payload])(ctx, dbContext) + (p.Payloads[payload])(ctx, dbContext) } func (p *Plugin) executeMiddlewares(ctx *MsgContext, db *DatabaseContext) bool { @@ -102,14 +92,6 @@ type MiddlewareBuilder struct { func NewMiddleware(name string, executor CommandExecutor) *MiddlewareBuilder { return &MiddlewareBuilder{name: name, executor: executor, order: 0, async: false} } -func (m *MiddlewareBuilder) SetName(name string) *MiddlewareBuilder { - m.name = name - return m -} -func (m *MiddlewareBuilder) SetExecutor(executor CommandExecutor) *MiddlewareBuilder { - m.executor = executor - return m -} func (m *MiddlewareBuilder) SetOrder(order int) *MiddlewareBuilder { m.order = order return m diff --git a/runners.go b/runners.go index 64988ec..488a008 100644 --- a/runners.go +++ b/runners.go @@ -44,6 +44,7 @@ func (b *RunnerBuilder) Build() Runner { } func (b *Bot) ExecRunners() { + b.logger.Infoln("Executing runners...") for _, runner := range b.runners { if !runner.Onetime && !runner.Async { b.logger.Warnf("Runner %s not onetime, but sync\n", runner.Name) -- 2.53.0 From 9ef9a240a400998fe67e9d8848f585fe67e17fd6 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Thu, 12 Feb 2026 11:47:58 +0300 Subject: [PATCH 16/16] v0.5.0 --- bot.go | 6 ------ tgapi/api.go | 2 +- tgapi/messages_types.go | 8 +++++--- utils.go | 6 ++++++ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bot.go b/bot.go index 884a3e2..d3cc5e9 100644 --- a/bot.go +++ b/bot.go @@ -262,12 +262,6 @@ func (b *Bot) Run() { middleware.Execute(ctx, b.dbContext) } - for _, plugin := range b.plugins { - if plugin.UpdateListener != nil { - (*plugin.UpdateListener)(ctx, b.dbContext) - } - } - if u.CallbackQuery != nil { b.handleCallback(u, ctx) } else { diff --git a/tgapi/api.go b/tgapi/api.go index bb3ba9f..4cda187 100644 --- a/tgapi/api.go +++ b/tgapi/api.go @@ -23,7 +23,7 @@ type Api struct { func NewAPI(token string) *Api { l := slog.CreateLogger().Level(utils.GetLoggerLevel()).Prefix("API") l.AddWriter(l.CreateJsonStdoutWriter()) - client := &http.Client{Timeout: time.Second * 10} + client := &http.Client{Timeout: time.Second * 45} return &Api{token, client, l} } func (api *Api) CloseApi() error { diff --git a/tgapi/messages_types.go b/tgapi/messages_types.go index 7a81c33..3662b20 100644 --- a/tgapi/messages_types.go +++ b/tgapi/messages_types.go @@ -1,5 +1,7 @@ package tgapi +import "git.nix13.pw/scuroneko/extypes" + type MessageReplyMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` } @@ -26,9 +28,9 @@ type Message struct { Text string `json:"text"` - Photo []*PhotoSize `json:"photo,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + Photo extypes.Slice[*PhotoSize] `json:"photo,omitempty"` + Caption string `json:"caption,omitempty"` + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` Date int `json:"date"` EditDate int `json:"edit_date"` diff --git a/utils.go b/utils.go index 7dcedde..debe5f1 100644 --- a/utils.go +++ b/utils.go @@ -1,5 +1,7 @@ package laniakea +import "git.nix13.pw/scuroneko/laniakea/utils" + func Ptr[T any](v T) *T { return &v } func Val[T any](p *T, def T) T { @@ -8,3 +10,7 @@ func Val[T any](p *T, def T) T { } return def } + +const VersionString = utils.VersionString + +var EscapeMarkdown = utils.EscapeMarkdown -- 2.53.0