Releases: tucnak/telebot
Telebot V3.3
Changelog
- Bot API 6.6, 6.7, 6.8, 6.9, 7.0, 7.1
- Implemented Boosts API support
- Improved Stickers API support
- Improved Album interaction
- More of handy
Context
helpers - New
telebot/react
package with reaction bindings - Embedded FS support for
telebot/layout
- Lots of minor fixes and improvements
Bot API 6.6: Stickers
Unfortunately, due to breaking the Stickers API update on the Telegram side, we had to break the backward compatibility with previous versions of Telebot as well. However, this allowed us to rework the API and make it feel better and clearer to use.
// 1. UploadSticker now accepts the StickerSetFormat and File
b.UploadSticker(to, tele.StickerStatic, tele.FromDisk("telebot.png"))
// 2. CreateStickerSet now works with multiple stickers
b.CreateStickerSet(to, &tele.StickerInput{
// ...
Input: []tele.InputSticker{
{File: tele.FromDisk("telebot1.png")},
{File: tele.FromDisk("telebot2.png")},
},
})
// 3. AddSticker is now called AddStickerToSet and accepts name and the InputSticker
b.AddStickerToSet(to, tele.InputSticker{
File: tele.FromDisk("telebot.png"),
})
Bot API 7.0, 7.1
Boosts
// 1. Get a list of user boosts for a particular chat
boosts, err := b.UserBoosts(chat, user)
if err != nil {
return err
}
// 2. Use boost fields
for _, boost := range boosts {
boost.ID
boost.AddDate()
boost.ExpirationDate()
...
}
// 3. Handle boost-related events
b.Handle(tele.OnBoost, func(c tele.Context) error {
boost := c.Boost()
boost.Chat
boost.Boost
...
})
Reactions
import (
tele "gopkg.in/telebot.v3"
"gopkg.in/telebot.v3/react"
)
// 1. Use a telebot/react package for the React shorthand
b.React(to, msg, react.React(react.ThumbUp, react.Fire))
// 2. Use ReactionOptions to add special options
b.React(to, msg, tele.ReactionOptions{
Reactions: []tele.Reaction{react.Heart},
Big: true,
})
Multiple Message Actions
b.ForwardMany(to, msgs)
b.CopyMany(to, msgs)
b.DeleteMany(to, msgs)
Other Features
Check out the whole diff: #658
More shorthands
- Use a new
Trigger
bot function to trigger the specific handler:
b.Handle("/start", func (c tele.Context) error {
return c.Send("Hello, World!")
})
b.Handle("/help", func (c tele.Context) error {
return b.Trigger("/start", c)
})
- Finally, a
SetCaption
function to add a caption to the first media of the album:
var album tele.Album
// Populate album dynamically...
album.SetCaption("Hey, hey, hey!")
msgs, err := b.SendAlbum(user, album)
if err != nil {
return err
}
- Handy
Context
helpers to removeCallbackResponse
from your code:
b.Handle(callback, func(c tele.Context) error {
return c.RespondText("This is a pop-up!")
// or ...
return c.RespondAlert("This is an alert!")
})
- Initialize a
telebot/layout
from the embedded FS:
import (
"embed"
tele "gopkg.in/telebot.v3"
"gopkg.in/telebot.v3/layout"
)
//go:embed layout
var fs embed.FS
func main() {
lt, err := layout.NewFromFS(fs, "bot.yml")
if err != nil {
panic(err)
}
b, err := tele.NewBot(lt.Settings())
if err != nil {
panic(err)
}
// Done!
}
Fixes and Improvements
- New
ErrIs
function to check if the given description matches the error (71ac299) - Fixed
stop
channel race (#641) - Improved
Context.Args
parsing (#651) - Added missed types and fields (#647, #648)
- Added more errors (#659)
- Some
*Chat
arguments changed toRecipient
(#568) middleware.RecoverFunc
now accepts theContext
(a26ba9f)- !! Renamings (0d0d5e7, 32b47a4, 435ad60)
Discussion
Telebot V3.2
Changelog
- Bot API 6.3, 6.4, 6.5
- Group's forum topics support
- Other minor fixes and improvements
Bot API 6.3, 6.4: Topics
// 1. Create a forum topic with specified settings
topic, err := b.CreateTopic(chat, &tele.Topic{Name: "Discussions"})
if err != nil {
return err
}
// 2. Use topic methods
b.CloseTopic(chat, topic)
b.ReopenTopic(chat, topic)
b.DeleteTopic(chat, topic)
b.HideGeneralTopic(chat)
b.UnhideGeneralTopic(chat)
...
// 3. Handle topics-related events
b.Handle(tele.OnTopicCreated, func(c tele.Context) error {
topic := c.Topic()
topic.Name
topic.ThreadID
})
Bot API 6.5: ReplyRecipient
// 1. Use a ReplyRecipient constructor for both
// `request_user` and `request_chat` params
var (
replyUser = &tele.ReplyRecipient{
ID: 1, // unique
Bot: tele.Flag(false),
Premium: tele.Flag(true),
}
replyChat = &tele.ReplyRecipient{
ID: 1, // unique
Channel: false, // required
Username: tele.Flag(true),
}
)
markup := &tele.ReplyMarkup{}
markup.Reply(
markup.Row(markup.User(replyUser)),
markup.Row(markup.Chat(replyChat)),
)
b.Send(to, "Share with me...", markup)
// 2. Handle the shared user or chat
b.Handle(tele.OnUserShared, func(c tele.Context) error {
user := c.Message().UserShared
log.Println("Shared user ID:", user.UserID)
})
Use a Flag
helper that returns a pointer to the given bool:
// Flag returns a pointer to the given bool.
// Useful for passing the three-state flags to a Bot API.
// For example, see ReplyRecipient type.
func Flag(b bool) *bool {
return &b
}
Fixes and Improvements
Bot.SetWebhook
error is loggable by default (#559)telebot/layout
fixes (7065335, 4c17ca7)- Fixed the middleware applying for groups (#588)
- More errors (#570, 699e5db)
- Added missed
is_member
field to theChatMember
(#615) - Added missed
custom_emoji_id
field to theSticker
(#579) - Fixed
Results.MarshalJSON
addressing inside for-loop (#589)
Discussion
Telebot V3.1
Changelog
- Bot API 6.0, 6.1, 6.2
telebot/layout
improvements- Changed panic-recovering behavior
- Source restructure and refactoring
- Other minor fixes and improvements
Web apps support
Use the new OnWebApp
event along with the WebApp
buttons field to interact with the new stunning web app functionality.
webApp := &tele.WebApp{
URL: "https://mywebapp.com",
}
b.Handle("/start", func(c tele.Context) error {
markup := b.NewMarkup()
markup.Inline(markup.WebApp("Open", webApp))
return c.Send("Open this app!", markup)
})
b.Handle(tele.OnWebApp, func(c tele.Context) error {
webapp := c.Message().WebAppData
// Use the data fields:
// webapp.Data
// webapp.Text
}
New Recover
middleware
Be careful with allowing panics inside your handlers after the v3.0.1
release, since panics' recovering by default was removed. Instead, make sure you've added the Recover
middleware in case you really need it:
b.Use(middleware.Recover())
b.Use(middleware.Logger())
// ...
telebot/layout
improvements
- Use new
tele.M
alias in your layout calls instead ofmap[string]any
declaration:
lt.Text(c, "start", tele.M{...})
- The new
CommandsLocale
function for localized commands:
# bot.yml
commands:
/help: '{{ text `cmd_help` }}'
# en.yml
cmd_help: Show the help message
# fr.yml
cmd_help: Afficher le message d'aide
for _, locale := range lt.Locales() {
b.SetCommands(locale, lt.CommandsLocale(locale))
}
layout.Config
is now usingviper
under the hood
config:
tiers:
default: standard
all:
- name: standard
limit: 5
delay: 10m
- name: premium
limit: 50
delay: 1h
// Instead of an old sequential method,
defaultTier := lt.Get("tiers").String("default")
// you can use viper's dot notation:
defaultTier := lt.String("tiers.default")
// Some clumsy methods were removed,
// so instead of lt.Each and lt.Index use:
for _, tier := range lt.Slice("tiers.all") {
dur := tier.Duration("delay")
}
// You can also unmarshal any key directly:
var tiers []struct {
Name string
Limit int
Delay time.Duration
}
lt.UnmarshalKey("tiers.all", &tiers)
Backward incompatible changes
Unfortunately, some of them had a place in the v3.1.0
release and we can't guarantee compatibility through all the minor versions after this. The main reason for it is the fact that Telegram itself allows the breaking changes to appear in their API, however in some cases you can't help it, and breaking becomes inevitable. We break the contract beforehand so that you're previously ready for the future breaking Bot API update.
Some of the changes you should be aware of:
Bot.OnError
field won't be exposed, useSettings.OnError
instead once at initialization- Aforementioned panic-recovering behavior is optional
File.FileSize
changed theint
type to theint64
voice_chat_*
fields renamed tovideo_chat_*
*ChatJoinRequest
functions renamed to*JoinRequest
Fixes
- One minute is the default HTTP client timeout now (#478)
- Handled video response from
sendDocument
(#481) Message.Media()
includes missedSticker
type (#520)- Cancel
Raw()
execution on bot stop (#532) DeleteCommands
function is fixed (#533)- Fixed the order in which layout template's
Funcs
are applied (#546)
Discussion
Telebot V3.0.1
Changelog
Sticker
is treated as aMedia
nowDeleteCommands
is working properly nowis_premium
field is added to theChat
Stop()
behavior improvements (#532)- New
tele.M
alias type for themap[string]any
to be used with layout package middleware.Recover()
is added instead of the default panic-recovering behaviorBot.OnError
is read-only now, instead pass the error handler once throughtele.Settings
Telebot V3
We're happy to finally announce V3 of Telebot framework — the best of its kind API for interacting with Telegram bots. There were many changes and innovations based on our and the community's negative experience, which had a place while using V2. We've tried to include all common and most convenient routing, handling, and middleware patterns. Although this branch was widely tested and is production-ready, many planned but unimplemented things are left, so we're going to introduce even more allure features in future major and minor versions.
Especial thanks to all our contributors who helped through these years in fixing bugs, improving, and maintaining API.
Changelog
gopkg.in/tucnak.v3
is the new import pathtele
is the new recommended alias- Bot API 5.3, 5.4, 5.5, 5.6, 5.7
- Completed list of API errors
- Better and clarified naming (#301)
- Added missed events (cb12b17)
- Got rid of
github.com/pkg/errors
package (#462) - Tons of other minor fixes and improvements
Introducing Context
Let's define a simple handler which responds to the /start
command using v2:
b.Handle("/start", func(m *tele.Message) {
_, err := b.Send(m.Sender, "Hello!")
if err != nil {
log.Println(err)
return
}
})
There'll be lots of similar calls in any advanced stateful Telegram bot, not only with b
bot instance but also with databases and other dependencies. The default handler function signature does not imply error handling, which is wrong. So, the first thing that suggests itself is a way to minimize errors check routine. We also need one strictly defined place where all errors come together with a corresponding event.
Secondly, while developing a complex bot, you often need to perform the same logic for different endpoint types. As an example, to send a help message whether replying to the user's command or responding to the button pressing. In v2 it will be two separate functions: one taking *Message
and another with *Callback
.
What if we combine all the possible handler types and encapsulate the different logic for different events? Here comes a Context
— an interface type, which implementation wraps an incoming update and provides a number of useful short-hands and helper functions.
b.Handle("/start", func(c tele.Context) error {
return c.Send("Hello!")
})
Isn't it handy? It's a one-line v3 versus 4-5 lines v2. Now, we force a user to return the error, so most likely it will be recorded. For this purpose, we can override a special OnError
callback:
b.OnError = func(err error, c tele.Context) {
if err != tele.ErrTrueResult {
log.Println(c.Sender().ID, err)
}
}
It also doesn't matter which type the event is — context can handle it and send the message in the current chat:
b.Handle("/start", sendHello)
b.Handle(&btnHello, sendHello)
We can go even further and let's say, edit the message if it is editable; otherwise, send it:
func sendHello(c tele.Context) error {
return c.EditOrSend("Hello!")
}
The same applies to all the functions in the Context
interface. Check them out here.
Introducing Middleware
You might notice that the context approach is somewhat similar to what we experience in most advanced HTTP server frameworks like echo
or gin
. What we're missing is an easier way to define and use middleware. The only method to do it was to wrap a poller with a custom MiddlewarePoller
which performs necessary logic processing incoming updates. When we have piles and piles of extra middleware functionality it becomes clumsy.
So how do we do it now? To register your own or some pre-defined middlewares from the telebot/middleware
package, there's a Use
function.
import "gopkg.in/telebot.v3/middleware"
// Global-scoped middleware:
b.Use(middleware.Logger()) // logs every incoming handled event
b.Use(middleware.AutoRespond()) // automatically responds to every callback
// Group-scoped middleware:
adminOnly := b.Group()
adminOnly.Use(middleware.Whitelist(adminIDs...))
adminOnly.Handle("/ban", onBan)
adminOnly.Handle("/kick", onKick)
// Handler-scoped middleware:
b.Handle(tele.OnText, onText, middleware.IgnoreVia())
It comes clear how to implement your own middleware by looking at built-in straightforward examples.
New OnMedia
endpoint
All media types are now associated with a Media
interface and all InputMedia
types — with an Inputtable
interface. Here perfectly fits the OnMedia
event, which matches any kind of media that wasn't handled by a specific handler.
b.Handle(tele.OnMedia, func(c tele.Context) error {
media := c.Message().Media()
// Now you can store media's kind and file ID:
kind := media.MediaType()
file := media.MediaFile()
// ...
})
Several useful helpers
A handy and my favorite Split
helper splits a list of buttons into the rows of them by a given maximum capacity for each row:
b.Handle("/things", func(c tele.Context) error {
var btns []tele.Btn
for _, thing := range things {
btns = append(btns, /* prepare a button */)
}
markup := b.NewMarkup()
markup.Inline(markup.Split(3, btns)...)
return c.Send("Choose a thing:", markup)
})
An input_field_placeholder
wrapper:
b.Handle("/name", func(c tele.Context) error {
return c.Send(
"Input your new name:",
tele.Placeholder("John Doe"),
)
})
Message's text/caption entities parser via EntityText
:
b.Handle(tele.OnText, func(c tele.Context) error {
m := c.Message()
var mentions []string
for _, ent := range m.Entities {
if ent.Type == tele.EntityMention {
mentions = append(mentions, m.EntityText(ent))
}
}
return c.Send(fmt.Sprintf("Mentions: %s.", strings.Join(mentions, ", ")))
})
Postponed message deletion:
b.Handle("/start", func(c tele.Context) error {
c.DeleteAfter(10 * time.Second)
return c.Send(...)
})
Introducing telebot/layout
This part, I believe, deserves another comprehensive description. It provides a lot of use-cases and allows you to separate the code and the business logic from a bot's content. A godoc
documentation is available here.
Check out some examples
People often complain about the lack of examples. We've prepared plenty of them: github.com/handybots. These are real and working bots opened for the good of the community.
Discussion
Telebot V2.5
Changelog
User identifiers can now be bigger than 2^31 - 1 and it is no longer possible to store them in a signed 32-bit integer type. User identifiers have up to 52 significant bits, so a 64-bit integer or double-precision float type is safe for storing them. Please make sure that your code can correctly handle such user identifiers.
Announcement
Telebot V2 is no longer maintained — this is the last major version. Currently, we're working on V3, which is much more advanced and has tons of helpful features and continuous support. As there're not that many breaking changes between two APIs, consider migrating to the latest v3
branch as soon as the beta will be released.
Discussion
Telebot V2.4
Changelog
- Bot API 5.0, 5.1, 5.2
SendAlbum
improvements (#398)
Telebot V2.3
Changelog
-
Bot API 4.9
-
Special
ErrTrueResult
error for updating methods -
Extended
b.Edit()
function:b.Edit(m, m.Text, newMarkup) b.Edit(m, "new <b>text</b>", tb.ModeHTML) b.Edit(m, &tb.ReplyMarkup{...}) b.Edit(m, &tb.Photo{File: ...}) b.Edit(m, tb.Location{42.1337, 69.4242})
-
Default parse mode:
pref := tb.Settings{ Token: "", ParseMode: tb.ModeMarkdown, } b, _ := tb.NewBot(pref) b.Send(to, "*text*") // default markdown mode b.Send(to, "<b>text</b>", tb.ModeHTML) // forced html mode
-
Verbose mode for outcoming requests:
pref := tb.Settings{ Token: "", Verbose: true, } b, _ := tb.NewBot(pref) b.Notify(to, tb.Typing)
[verbose] telebot: sent request Method: sendChatAction Params: { "action": "typing", "chat_id": "..." } Response: { "ok": true, "result": true }
Fixes
Telebot V2.2
For this release, aside from Bot API implementation, we've prepared many new useful features.
Changelog
- Completed Webhook, Games, Stickers and Payments APIs
- Synchronous mode and serverless support (#219)
- Keyboard constructors (#290)
- Special
ChatID
recipient type (#263)
Serverless
Now it's possible to use telebot
together with serverless providers like AWS, Azure, etc... Thanks to one of the package's contributors, you can check out the exhaustive example in examples/awslambdaechobot.
pref := tb.Settings{
Token: "",
Synchronous: true,
}
b, err := tb.NewBot(pref)
// ...
Keyboard constructors
Use special helper functions and types to decrease boilerplate across the code. The new keyboards builder make their definition easier. Look into updated README Keyboards
section for details.
menu := &ReplyMarkup{ResizeReplyKeyboard: true}
var (
// Reply buttons.
btnHelp = menu.Text("ℹ Help")
btnSettings = menu.Text("⚙ Settings")
)
menu.Reply(
menu.Row(btnHelp),
menu.Row(btnSettings),
)
b.Handle(&btnHelp, func(m *tb.Message) {...})
b.Handle(&btnSettings, func(m *tb.Message) {...})
ChatID
type
It was a bit confusing to work with specific chat IDs. You had to wrap integer into &tb.Chat{}
every time you wanted to send a message. Imagine you have a config file with a bunch of defined group or channel IDs. Now you can use your int64
values directly with functions which accept Recipient
interface.
type Config struct {
AdminGroup tb.ChatID `yaml:"admin_group_id"`
AdsChannel tb.ChatID `yaml:"ads_channel_id"`
}
b.Send(conf.AdminGroup, "message")
b.Send(conf.AdsChannel, "message")
Fixes
- Added
OnAnimation
endpoint - Fixed regular expression for errors handling
Action
fields were removed from Buttonsb.Forward()
changed to takeEditable
instead of*Message
Telebot V2.1
Finally, a new Telebot v2.1
release with a lot of minor fixes, additions and new methods implementations.
Changelog
- Practically full implemented Bot API 4.8
- Started code coverage process (now it's about 30%)
- A convenient way to handle Telegram errors
- A lot of bug fixes
Errors
From this release, you will be able to easily check for specific Telegram errors. We have a bunch of pre-defined Bot API errors and their descriptions in errors.go
file. The work is still in progress, so feel free to contribute and to add missed entries. All errors are prefixed with telebot:
if it's telebot-related or with telegram:
if it's an API response.
msg, err := b.Send(user, "Hello World!")
if err != nil {
if err == tb.ErrBlockedByUser {
// remove user from database
}
// ...
}