| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- (in-package :cl-user)
- (defpackage chatikbot.telegram
- (:use :cl :chatikbot.utils)
- (:export :*telegram-token*
- :+telegram-max-callback-data-length+
- :telegram-get-updates
- :telegram-get-me
- :telegram-set-webhook
- :telegram-send-message
- :telegram-forward-message
- :telegram-send-photo
- :telegram-send-audio
- :telegram-send-document
- :telegram-send-sticker
- :telegram-send-video
- :telegram-send-voice
- :telegram-send-video-note
- :telegram-send-media-group
- :telegram-send-location
- :telegram-send-venue
- :telegram-edit-message-live-location
- :telegram-stop-message-live-location
- :telegram-send-contact
- :telegram-send-chat-action
- :telegram-send-get-user-profile-photos
- :telegram-send-get-file
- :telegram-answer-callback-query
- :telegram-edit-message-text
- :telegram-edit-message-caption
- :telegram-edit-message-reply-markup
- :telegram-delete-message
- :telegram-answer-inline-query
- :telegram-file-contents
- :telegram-inline-keyboard-markup
- :telegram-reply-keyboard-markup
- :telegram-reply-keyboard-hide
- :telegram-force-reply
- :bot-send-message))
- (in-package :chatikbot.telegram)
- (defvar *telegram-token* nil "Telegram bot token")
- (defparameter +telegram-api-format+ "https://api.telegram.org/bot~A/~A")
- (defparameter +telegram-file-format+ "https://api.telegram.org/file/bot~A/~A")
- (defparameter +telegram-max-callback-data-length+ 64)
- (defvar *telegram-timeout* 30 "Default Telegram timeout")
- (defun %telegram-api-call (method &optional args)
- (handler-case
- (let* ((params (loop for (k . v) in args when v
- collect (cons
- (princ-to-string k)
- (if (pathnamep v) v
- (princ-to-string v)))))
- (timeout (+ 5 (or (aget "timeout" args)
- *telegram-timeout*)))
- (response
- (json-request (format nil +telegram-api-format+
- *telegram-token* method)
- :method :post
- :content params
- :read-timeout timeout)))
- (unless (aget "ok" response)
- (error (aget "description" response)))
- (aget "result" response))
- (dex:http-request-forbidden (e)
- (log:info "Forbidden" e))))
- (defun telegram-get-updates (&key offset limit timeout)
- (%telegram-api-call
- "getUpdates"
- (list (cons "offset" offset)
- (cons "limit" limit)
- (cons "read-timeout" timeout))))
- (defun telegram-get-me ()
- (%telegram-api-call "getMe"))
- (defun telegram-set-webhook (&optional url certificate)
- (%telegram-api-call "setWebhook" (list (cons "url" url) (cons "certificate" certificate))))
- (defun telegram-send-message (chat-id text &key parse-mode disable-web-preview disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendMessage"
- (list (cons "chat_id" chat-id)
- (cons "text" text)
- (cons "parse_mode" parse-mode)
- (cons "disable_web_page_preview" disable-web-preview)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-forward-message (chat-id from-chat-id message-id)
- (%telegram-api-call
- "forwardMessage"
- `(("chat_id" . ,chat-id)
- ("from_chat_id" . ,from-chat-id)
- ("message_id" . ,message-id))))
- (defun telegram-send-photo (chat-id photo &key caption disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendPhoto"
- (list (cons "chat_id" chat-id)
- (cons "photo" photo)
- (cons "caption" caption)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-audio (chat-id audio &key caption duration performer title disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendAudio"
- (list (cons "chat_id" chat-id)
- (cons "audio" audio)
- (cons "caption" caption)
- (cons "duration" duration)
- (cons "performer" performer)
- (cons "title" title)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-document (chat-id document &key caption disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendDocument"
- (list (cons "chat_id" chat-id)
- (cons "document" document)
- (cons "caption" caption)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-sticker (chat-id sticker &key disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendSticker"
- (list (cons "chat_id" chat-id)
- (cons "sticker" sticker)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-video (chat-id video &key duration width height caption disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendVideo"
- (list (cons "chat_id" chat-id)
- (cons "video" video)
- (cons "duration" duration)
- (cons "width" width)
- (cons "height" height)
- (cons "caption" caption)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-voice (chat-id voice &key caption duration disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendVoice"
- (list (cons "chat_id" chat-id)
- (cons "voice" voice)
- (cons "caption" caption)
- (cons "duration" duration)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-video-note (chat-id video-note &key duration length disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendVideoNote"
- (list (cons "chat_id" chat-id)
- (cons "video_note" video-note)
- (cons "duration" duration)
- (cons "length" length)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-media-group (chat-id media &key disable-notification reply-to)
- (%telegram-api-call
- "sendMediaGroup"
- (list (cons "chat_id" chat-id)
- (cons "media" media)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to))))
- (defun telegram-send-location (chat-id latitude longitude &key live-period disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendLocation"
- (list (cons "chat_id" chat-id)
- (cons "latitude" latitude)
- (cons "longitude" longitude)
- (cons "live_period" live-period)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-edit-message-live-location (latitude longitude &key chat-id message-id inline-message-id reply-markup)
- (%telegram-api-call
- "editMessageLiveLocation"
- (list (cons "chat_id" chat-id)
- (cons "message_id" message-id)
- (cons "inline_message_id" inline-message-id)
- (cons "latitude" latitude)
- (cons "longitude" longitude)
- (cons "reply_markup" reply-markup))))
- (defun telegram-stop-message-live-location (&key chat-id message-id inline-message-id reply-markup)
- (%telegram-api-call
- "stopMessageLiveLocation"
- (list (cons "chat_id" chat-id)
- (cons "message_id" message-id)
- (cons "inline_message_id" inline-message-id)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-venue (chat-id latitude longitude title address &key foursquare-id disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendVenue"
- (list (cons "chat_id" chat-id)
- (cons "latitude" latitude)
- (cons "longitude" longitude)
- (cons "title" title)
- (cons "address" address)
- (cons "foursquare_id" foursquare-id)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-contact (chat-id phone-number first-name &key last-name disable-notification reply-to reply-markup)
- (%telegram-api-call
- "sendContact"
- (list (cons "chat_id" chat-id)
- (cons "phone_number" phone-number)
- (cons "first_name" first-name)
- (cons "last_name" last-name)
- (cons "disable_notification" disable-notification)
- (cons "reply_to_message_id" reply-to)
- (cons "reply_markup" reply-markup))))
- (defun telegram-send-chat-action (chat-id action)
- (%telegram-api-call
- "sendChatAction"
- (list (cons "chat_id" chat-id)
- (cons "action" action))))
- (defun telegram-get-user-profile-photos (user-id &key offset limit)
- (%telegram-api-call
- "getUserProfilePhotos"
- (list (cons "user_id" user-id)
- (cons "offset" offset)
- (cons "limit" limit))))
- (defun telegram-get-file (file-id)
- (%telegram-api-call "getFile" (list (cons "file_id" file-id))))
- (defun telegram-answer-callback-query (query-id &key text show-alert)
- (%telegram-api-call
- "answerCallbackQuery"
- (list (cons "callback_query_id" query-id)
- (cons "text" text)
- (cons "show_alert" show-alert))))
- (defun telegram-edit-message-text (text &key chat-id message-id inline-message-id parse-mode disable-web-preview reply-markup)
- (%telegram-api-call
- "editMessageText"
- (list (cons "chat_id" chat-id)
- (cons "message_id" message-id)
- (cons "inline_message_id" inline-message-id)
- (cons "text" text)
- (cons "parse_mode" parse-mode)
- (cons "disable_web_page_preview" disable-web-preview)
- (cons "reply_markup" reply-markup))))
- (defun telegram-edit-message-caption (caption &key chat-id message-id inline-message-id reply-markup)
- (%telegram-api-call
- "editMessageCaption"
- (list (cons "chat_id" chat-id)
- (cons "message_id" message-id)
- (cons "inline_message_id" inline-message-id)
- (cons "caption" caption)
- (cons "reply_markup" reply-markup))))
- (defun telegram-edit-message-reply-markup (reply-markup &key chat-id message-id inline-message-id)
- (%telegram-api-call
- "editMessageReplyMarkup"
- (list (cons "chat_id" chat-id)
- (cons "message_id" message-id)
- (cons "inline_message_id" inline-message-id)
- (cons "reply_markup" reply-markup))))
- (defun telegram-delete-message (chat-id message-id)
- (%telegram-api-call
- "deleteMessage" (list (cons "chat_id" chat-id)
- (cons "message_id" message-id))))
- (defun telegram-answer-inline-query (query-id results &key cache-time is-personal next-offset switch-pm-text switch-pm-parameter)
- (%telegram-api-call
- "answerInlineQuery"
- (list (cons "inline_query_id" query-id)
- (cons "results" (plist-json results))
- (cons "cache_time" cache-time)
- (cons "is_personal" is-personal)
- (cons "next_offset" next-offset)
- (cons "switch_pm_text" switch-pm-text)
- (cons "switch_pm_parameter" switch-pm-parameter))))
- (defun telegram-file-contents (file-id)
- (let* ((file (telegram-get-file file-id))
- (file-path (aget "file_path" file))
- (file-url (format nil +telegram-file-format+ *telegram-token* file-path)))
- (http-request file-url :force-binary t)))
- (defun telegram-inline-keyboard-markup (inline-keyboard)
- (when inline-keyboard
- (plist-json
- (list :inline-keyboard inline-keyboard))))
- (defun telegram-reply-keyboard-markup (keyboard &key resize-keyboard one-time-keyboard selective)
- (when keyboard
- (plist-json
- (list :keyboard keyboard
- :resize-keyboard resize-keyboard
- :one-time-keyboard one-time-keyboard
- :selective selective))))
- (defun telegram-reply-keyboard-hide (&optional selective)
- (plist-json (list :hide-keyboard t :selective selective)))
- (defun telegram-force-reply (&optional selective)
- (plist-json (list :force-reply t :selective selective)))
- ;; Simplified interface
- ;;
- (defun bot-send-message (message &key (chat-id *chat-id*) parse-mode disable-web-preview disable-notification reply-to reply-markup duration)
- (handler-case (if (consp message)
- (if (keywordp (car message))
- (case (car message)
- (:text (telegram-send-message chat-id (cdr message)
- :parse-mode parse-mode
- :disable-web-preview disable-web-preview
- :disable-notification disable-notification
- :reply-to reply-to
- :reply-markup reply-markup))
- (:voice (telegram-send-voice chat-id (cdr message)
- :duration duration
- :reply-to reply-to
- :reply-markup reply-markup))
- (:sticker (telegram-send-sticker chat-id (cdr message)
- :reply-to reply-to
- :reply-markup reply-markup)))
- (mapc #'(lambda (m) (bot-send-message m
- :chat-id chat-id
- :parse-mode parse-mode
- :disable-web-preview disable-web-preview
- :disable-notification disable-notification
- :reply-to reply-to
- :reply-markup reply-markup
- :duration duration)) message))
- (telegram-send-message chat-id message
- :parse-mode parse-mode
- :disable-web-preview disable-web-preview
- :disable-notification disable-notification
- :reply-to reply-to
- :reply-markup reply-markup))
- (error (e)
- (log:error e))))
|