- Description: Telegram Bot
API
, based on sovietspaceship's work but mostly rewritten. - Licence:
MIT
- Author: Alexander Artemenko [email protected]
- Homepage: https://40ants.com/cl-telegram-bot/
- Bug tracker: https://github.com/40ants/cl-telegram-bot/issues
- Source control: GIT
- Depends on: alexandria, anaphora, arrows, bordeaux-threads, cl-ppcre, cl-strings, closer-mop, dexador, jonathan, kebab, log4cl, serapeum, str, trivial-backtrace, yason
You can install this library from Quicklisp, but you want to receive updates quickly, then install it from Ultralisp.org:
(ql-dist:install-dist "http://dist.ultralisp.org/"
:prompt nil)
(ql:quickload :cl-telegram-bot)
The system uses CLOS
to add new methods to process incoming messages.
To create a simple bot, all you need is to define on-message
method.
If you want to match on a particular command, like /help
or /make-me-happy 7 times
,
then you better to define a on-command
method.
During messages processing, function (reply "some text")
is available, which will send
given text into the right chat. Also, there is send-message
and other function exists
which allow your bot to post messages, images and other media into the any chat.
Here is example of a simple bot which reacts on the text message and /echo
command:
CL-USER> (defpackage the-bot (:use :cl :cl-telegram-bot))
#<Package "THE-BOT">
CL-USER> (in-package the-bot)
#<Package "THE-BOT">
THE-BOT> (defbot echo-bot)
MAKE-ECHO-BOT
THE-BOT> (defmethod on-message ((bot echo-bot)
text)
(reply text))
#<STANDARD-METHOD ON-MESSAGE (ECHO-BOT T)>
THE-BOT> (defmethod on-command ((bot echo-bot)
(command (eql :help))
text)
(declare (ignorable text))
(reply "Just send me any text and I'll reply with the same text."))
#<STANDARD-METHOD ON-COMMAND (ECHO-BOT (EQL :HELP) T)>
THE-BOT> (defmethod on-command ((bot echo-bot)
(command (eql :start))
text)
(declare (ignorable text))
(reply "Welcome Lisper! Have a fun, playing with cl-telegram-bot!"))
#<STANDARD-METHOD ON-COMMAND (ECHO-BOT (EQL :START) T)>
Now, stop for the minute, open your Telegram client, and create a new bot using the BotFather bot:
When you've got token, return to the REPL
and start our bot:
THE-BOT> (start-processing (make-echo-bot "5205125**********************************")
:debug t)
<INFO> [08:31:09] cl-telegram-bot core.lisp (start-processing) - Starting thread to process updates for CL-TELEGRAM-BOT/CORE::BOT: #<ECHO-BOT id=0>
#<PROCESS telegram-bot(33) [Reset] #x30200709246D>
THE-BOT>
This will start a new thread for processing incoming messages.
Now, find your bot in the Telegram client:
And start communicating with him:
package cl-telegram-bot/bot
class bot
()
Readers
reader api-uri
(bot) (:API-URI = "https://api.telegram.org/")
reader bot-info
(bot) (= nil)
This slot will be filled with cl-telegram-bot/user:user
object on first access using a call to cl-telegram-bot/user:get-me
function.
reader debug-mode
(bot) (:debug-mode = nil)
When debug mode is T, then interactive debugger will be called on each error.
reader file-endpoint
(bot) (:file-endpoint = nil)
HTTPS
file-endpoint
reader get-endpoint
(bot) (:endpoint)
HTTPS
endpoint
reader get-last-update-id
(bot) (= 0)
Update id
reader sent-commands-cache
(bot) (= nil)
Command processing code will use this cache to update commands list on the server
when a new method for cl-telegram-bot/entities/command:on-command
generic-function is defined.
This slot is for internal use.
reader token
(bot) (:token = nil)
Bot token given by BotFather
Accessors
accessor api-uri
(bot) (:API-URI = "https://api.telegram.org/")
accessor debug-mode
(bot) (:debug-mode = nil)
When debug mode is T, then interactive debugger will be called on each error.
accessor file-endpoint
(bot) (:file-endpoint = nil)
HTTPS
file-endpoint
accessor get-last-update-id
(bot) (= 0)
Update id
accessor sent-commands-cache
(bot) (= nil)
Command processing code will use this cache to update commands list on the server
when a new method for cl-telegram-bot/entities/command:on-command
generic-function is defined.
This slot is for internal use.
accessor token
(bot) (:token = nil)
Bot token given by BotFather
macro defbot
name &optional slots options
Use this macro to define a class of your Telegram bot.
package cl-telegram-bot/callback
class callback
()
Readers
reader callback-data
(callback) (:data)
reader callback-id
(callback) (:id)
reader callback-message
(callback) (:message)
generic-function make-callback
bot callback-data
Called when user clicks callback button. Should return an instance of callback
class.
Application may override this method to return objects of different callback classes depending on
callback-data string. This way it mab be easier to define more specific methods for
on-callback
generic-function.
generic-function on-callback
bot callback
Called when user clicks callback button. Second argument is an object of CALLBACK
type.
package cl-telegram-bot/chat
class channel
(base-group)
class chat
()
Readers
reader get-chat-id
(chat) (:id)
reader get-has-protected-content
(chat) (:has-protected-content)
reader get-message-auto-delete-time
(chat) (:message-auto-delete-time)
reader get-raw-data
(chat) (:raw-data)
reader get-username
(chat) (:username)
class group
(base-group)
class private-chat
(chat)
Readers
reader get-bio
(private-chat) (:bio)
reader get-first-name
(private-chat) (:first-name)
reader get-has-private-forwards
(private-chat) (:has-private-forwards)
reader get-last-name
(private-chat) (:last-name)
class super-group
(base-group)
Readers
reader get-can-set-sticker-set
(super-group) (:can-set-sticker-set)
reader get-join-by-request
(super-group) (:join-by-request)
reader get-join-to-send-messages
(super-group) (:join-to-send-messages)
reader get-slow-mode-delay
(super-group) (:slow-mode-delay)
reader get-sticker-set-name
(super-group) (:sticker-set-name)
generic-function get-chat
obj
Returns a chat associated with object.
Object could be a message, update, callback, etc. Should return an object of chat
class or NIL
.
Some types of updates aren't bound to a chat. In this case a method should return NIL
.
function delete-chat-photo
bot-var1 chat
https://core.telegram.org/bots/api#deletechatphoto
function export-chat-invite-link
bot-var1 chat
https://core.telegram.org/bots/api#exportchatinvitelink
function get-chat-administrators
bot-var1 chat
https://core.telegram.org/bots/api#getchatadministrators
function get-chat-by-id
bot-var1 chat-id
https://core.telegram.org/bots/api#getchat
function get-chat-member
bot-var1 chat user-id
https://core.telegram.org/bots/api#getchatmember
function get-chat-members-count
bot-var1 chat
https://core.telegram.org/bots/api#getchatmemberscount
function kick-chat-member
bot-var1 chat user-id until-date
https://core.telegram.org/bots/api#kickchatmember
function leave-chat
bot-var1 chat
https://core.telegram.org/bots/api#leavechat
function pin-chat-message
bot-var1 chat message-id disable-notification
https://core.telegram.org/bots/api#pinchatmessage
function promote-chat-member
bot-var1 chat user-id can-change-info can-post-messages can-edit-messages can-delete-messages can-invite-users can-restrict-members can-pin-messages can-promote-members
https://core.telegram.org/bots/api#promotechatmember
function restrict-chat-member
bot-var1 chat user-id until-date can-send-messages can-send-media-messages can-send-other-messages can-add-web-page-previews
https://core.telegram.org/bots/api#restrictchatmember
function send-chat-action
bot-var1 chat action
https://core.telegram.org/bots/api#sendchataction
function set-chat-description
bot-var1 chat description
https://core.telegram.org/bots/api#setchatdescription
function set-chat-photo
bot-var1 chat photo
https://core.telegram.org/bots/api#setchatphoto
function set-chat-title
bot-var1 chat title
https://core.telegram.org/bots/api#setchattitle
function unban-chat-member
bot-var1 chat user-id
https://core.telegram.org/bots/api#unbanchatmember
function unpin-chat-message
bot-var1 chat
https://core.telegram.org/bots/api#unpinchatmessage
package cl-telegram-bot/core
class reply
(response-with-text)
generic-function on-command
bot command rest-text
This method will be called for each command. First argument is a keyword. If user input was /save_note, then first argument will be :save-note.
By default, logs call and does nothing.
generic-function on-message
bot text
This method gets called with raw text from the message. By default it does nothing.
function reply
text &rest args &key parse-mode disable-web-page-preview disable-notification reply-to-message-id reply-markup (immediately *reply-immediately*)
Works like a send-message
, but only when an incoming message is processed.
Automatically sends reply to a chat from where current message came from.
function start-processing
BOT &KEY DEBUG (DELAY-BETWEEN-RETRIES 10) (THREAD-NAME "telegram-bot")
function stop-processing
bot
macro defbot
name &optional slots options
Use this macro to define a class of your Telegram bot.
package cl-telegram-bot/entities/command
class bot-command
(entity)
Readers
reader bot-username
(bot-command) (:bot-username)
reader get-command
(bot-command) (:command)
reader get-rest-text
(bot-command) (:rest-text)
generic-function on-command
bot command rest-text
This method will be called for each command. First argument is a keyword. If user input was /save_note, then first argument will be :save-note.
By default, logs call and does nothing.
package cl-telegram-bot/entities/generic
generic-function make-entity-internal
entity-type payload data
Extendable protocol to support entities of different kinds. First argument is a keyword, denoting a type of the entity. Payload is an object of type `message'. And data is a plist with data, describing the entity.
function make-entity
payload data
package cl-telegram-bot/envelope
class channel-post
(envelope)
This container wraps cl-telegram-bot/message:message
when somebody sends a message to a channel.
class edited-channel-post
(envelope)
This container wraps cl-telegram-bot/message:message
when somebody edits a message in a channel.
class edited-message
(envelope)
This container wraps cl-telegram-bot/message:message
when user edits a message.
class envelope
()
This is the container for a message. From the type of container we can understand if this message was sent to a channel or maybe edited, etc.
Readers
reader wrapped-message
(envelope) (:message)
function channel-post-p
Returns T if current message was posted to a channel.
function edited-message-p
Returns T if current message is an update for existing message in the channel of group chat.
package cl-telegram-bot/inline-keyboard
class callback-button
(inline-keyboard-button)
Readers
reader callback-button-data
(callback-button) (:data)
class inline-keyboard-button
()
Base class for all inline keyboard buttons.
API
: https://core.telegram.org/bots/api#inlinekeyboardbutton
Readers
reader button-text
(inline-keyboard-button) (:text)
class inline-keyboard
()
Represents an inline keyboard as specified in API
https://core.telegram.org/bots/api#inlinekeyboardmarkup.
Readers
reader keyboard-rows
(inline-keyboard) (:rows = nil)
class url-button
(inline-keyboard-button)
Readers
reader button-url
(url-button) (:data)
function answer-callback-query
bot callback &key text show-alert url
https://core.telegram.org/bots/api#answercallbackquery
function callback-button
text data
Creates a button which will call a callback.
function inline-keyboard
rows
Returns an inline keyboard which can be passed
to cl-telegram-bot/response:reply
(1
2
) as REPLY-MARKUP
argument.
Each row should be a list of inline-keyboard-button
objects or a single
object of this class. In latter case, such row will have only one button.
function url-button
text url
Creates a button which will open an url.
package cl-telegram-bot/markup
generic-function to-markup
obj
Transforms object into markup of Telegram API
.
Methods of this class should return a hash-table, representing OBJ
in terms of Telegram API
.
package cl-telegram-bot/message
class animation-message
(file-message)
class animation
(file temporal spatial)
class audio-message
(file-message)
class audio
(file temporal)
Readers
reader get-performer
(audio) (:performer)
Performer of the audio as defined by sender or by audio tags.
reader get-title
(audio) (:title)
Title of the audio as defined by sender or by audio tags.
class document-message
(file-message)
class document
(file)
class file-message
(message)
Readers
reader get-file
(file-message) (:file)
class file
()
Readers
reader get-file-id
(file) (:file-id)
Identifier for this file, which can be used to download or reuse the file.
reader get-file-name
(file) (:file-name)
Original filename as defined by sender.
reader get-file-size
(file) (:file-size)
File size in bytes.
reader get-file-unique-id
(file) (:file-unique-id)
Unique identifier for this file, which is supposed to be the same over time and for different bots. Can't be used to download or reuse the file.
reader get-mime-type
(file) (:mime-type)
MIME
type of the file as defined by sender.
class message
()
Readers
reader get-caption
(message) (:caption)
Caption for the animation, audio, document, photo, video or voice.
reader get-chat
(message) (:chat)
reader get-entities
(message) (:entities = nil)
reader get-forward-from
(message) (:forward-from)
For forwarded messages, sender of the original message.
reader get-forward-from-chat
(message) (:forward-from-chat)
For messages forwarded from channels or from anonymous administrators, information about the original sender chat.
reader get-forward-sender-name
(message) (:forward-sender-name)
For forwarded messages, sender of the original message.
reader get-message-id
(message) (:id)
reader get-raw-data
(message) (:raw-data)
reader get-sender-chat
(message) (:sender-chat)
Sender of the message, sent on behalf of a chat. For example, the channel itself for channel posts, the supergroup itself for messages from anonymous group administrators, the linked channel for messages automatically forwarded to the discussion group.
reader get-text
(message) (:text)
class photo-message
(file-message)
Readers
reader get-photo-options
(photo-message) (:photo-options)
class photo
(file spatial)
class reply
(message)
Readers
reader get-reply-to-message
(reply) (:reply-to-message)
class spatial
()
Readers
reader get-height
(spatial) (:height)
File height as defined by sender.
reader get-width
(spatial) (:width)
File width as defined by sender.
class sticker-message
(file-message)
class sticker
(file spatial)
Readers
reader get-emoji
(sticker) (:emoji)
Emoji associated with the sticker
reader get-is-animated
(sticker) (:is-animated)
True if the sticker is animated.
reader get-is-video
(sticker) (:is-video)
True if the sticker is a video sticker.
reader get-set-name
(sticker) (:set-name)
Name of the sticker set to which the sticker belongs.
class temporal
()
Readers
reader get-duration
(temporal) (:duration)
Duration of the file in seconds as defined by sender.
class unispatial
()
Readers
reader get-length
(unispatial) (:length)
class video-message
(file-message)
class video-note-message
(file-message)
class video-note
(file temporal unispatial)
class video
(file temporal spatial)
class voice-message
(file-message)
class voice
(file temporal)
generic-function on-message
bot text
This method gets called with raw text from the message. By default it does nothing.
generic-function send-animation
bot chat animation &rest options &key caption parse-mode caption-entities duration width height thumb disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
Sends animation to a chat.
generic-function send-audio
bot chat audio &rest options &key caption parse-mode caption-entities duration performer title thumb disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
generic-function send-document
bot chat document &rest options &key caption parse-mode caption-entities disable-content-type-detection thumb disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
generic-function send-photo
bot chat photo &rest options &key caption parse-mode caption-entities disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
generic-function send-sticker
bot chat sticker &rest options &key disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
A function to send sticker.
generic-function send-video
bot chat video &rest options &key caption parse-mode caption-entities duration width height thumb disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
generic-function send-video-note
bot chat video-note &rest options &key caption parse-mode caption-entities duration length thumb disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
generic-function send-voice
bot chat voice &rest options &key caption parse-mode caption-entities duration disable-notification protect-content reply-to-message-id allow-sending-without-reply reply-markup
function delete-message
bot chat message
https://core.telegram.org/bots/api#deletemessage
function forward-message
bot chat from-chat message &key disable-notification
https://core.telegram.org/bots/api#forwardmessage
function get-current-bot
Returns a bot to which message was addressed.
function get-current-chat
Returns a chat where currently processing message was received.
function get-current-message
Returns currently processed message.
function make-message
data
function send-message
bot chat text &rest options &key parse-mode disable-web-page-preview disable-notification reply-to-message-id (autosplit nil) reply-markup
https://core.telegram.org/bots/api#sendmessage
package cl-telegram-bot/network
condition request-error
(error)
Readers
reader what
(request-error) (:what)
function make-request
bot name &rest options &key (streamp nil) (timeout 3) &allow-other-keys
Perform HTTP
request to 'name API
method with 'options JSON
-encoded object.
function set-proxy
proxy
package cl-telegram-bot/payments
generic-function on-pre-checkout-query
bot query
Called when user enters payment method credentials and hit "Pay" button. Second argument is an object of PRE-CHECKOUT-QUERY
type.
A method should respond with with a call to answer-pre-checkout-query
function.
function answer-pre-checkout-query
bot pre-checkout-query &key error-message
If ERROR-MESSAGE
argument was given, then response considered is not OK
and transaction will be cancelled.
https://core.telegram.org/bots/api#answerprecheckoutquery
function answer-shipping-query
b shipping-query-id ok &key shipping-options error-message
https://core.telegram.org/bots/api#answershippingquery
function send-invoice
b chat-id title description payload provider-token start-parameter currency prices &key photo-url photo-size photo-width photo-height need-name need-phone-number need-email need-shipping-address is-flexible disable-notification reply-to-message-id reply-markup
https://core.telegram.org/bots/api#sendinvoice
package cl-telegram-bot/pipeline
generic-function process
bot object
This method is called by when processing a single update. It is called multiple times on different parts of an update. Whole pipeline looks like that:
For each update we call: process(update) process(update.payload) For each entity in payload: process(entity)
package cl-telegram-bot/response
class alert
(response-with-text)
class notify
(response-with-text)
class open-url
(response)
Readers
reader url-to-open
(open-url) (:text)
class reply
(response-with-text)
class response-with-text
(response)
Readers
reader response-text
(response-with-text) (:text)
class response
()
Readers
reader rest-args
(response) (:args)
function alert
text
Works like a send-message
, but only when an incoming message is processed.
Automatically sends reply to a chat from where current message came from.
function notify
text
Works like a send-message
, but only when an incoming message is processed.
Automatically sends reply to a chat from where current message came from.
function open-url
url
Works like a send-message
, but only when an incoming message is processed.
Automatically sends reply to a chat from where current message came from.
function reply
text &rest args &key parse-mode disable-web-page-preview disable-notification reply-to-message-id reply-markup (immediately *reply-immediately*)
Works like a send-message
, but only when an incoming message is processed.
Automatically sends reply to a chat from where current message came from.
package cl-telegram-bot/response-processing
condition interrupt-processing
()
generic-function process-response
bot message response
Processes immediate responses of different types.
function interrupt-processing
package cl-telegram-bot/update
class update
()
Readers
reader get-payload
(update) (:payload)
reader get-raw-data
(update) (:raw-data)
reader get-update-id
(update) (:id)
generic-function process-updates
bot
By default, this method starts an infinite loop and fetching new updates using long polling.
function make-update
data
package cl-telegram-bot/user
class user
()
Readers
reader bot-p
(user) (:is-bot)
reader can-connect-to-business-p
(user) (:can-connect-to-business = nil)
reader can-join-groups-p
(user) (:can-join-groups = nil)
reader can-read-all-group-messages-p
(user) (:can-read-all-group-messages = nil)
reader first-name
(user) (:first-name)
reader is-premium
(user) (:is-premium = nil)
reader language-code
(user) (:language-code = nil)
reader last-name
(user) (:last-name = nil)
reader raw-data
(user) (:raw-data)
reader supports-inline-queries-p
(user) (:supports-inline-queries = nil)
reader user-id
(user) (:id)
reader username
(user) (:username = nil)
generic-function get-user-info
obj
Returns a user
object related to the object.
If object is not bound to a user, then NIL
should be returned.
function get-me
bot
https://core.telegram.org/bots/api#getme
package cl-telegram-bot/utils
function api-response-to-plist
plist
Transforms a plist with keys like :|foo_bar| into a plist with keys like :foo-bar.
This can be useful to pass data into CL
object contructors.
function make-keyword
text
function obfuscate
url
function split-by-lines
text &key (max-size 4096) (trim-whitespaces-p t)
- Rei – initial version.
- Alexander Artemenko – large refactoring, usage of
CLOS
classes, etc.