├── tests ├── __init__.py └── test_data │ ├── record.mp3 │ ├── record.ogg │ ├── record.wav │ └── test_video.mp4 ├── requirements.txt ├── telebot ├── ext │ ├── __init__.py │ ├── aio │ │ └── __init__.py │ ├── sync │ │ ├── __init__.py │ │ └── webhooks.py │ └── reloader.py ├── version.py ├── storage │ ├── __init__.py │ ├── base_storage.py │ └── memory_storage.py ├── asyncio_storage │ ├── __init__.py │ ├── base_storage.py │ └── memory_storage.py └── service_utils.py ├── docs ├── source │ ├── _static │ │ ├── logo.png │ │ └── logo2.png │ ├── types.rst │ ├── util.rst │ ├── formatting.rst │ ├── calldata.rst │ ├── quick_start.rst │ ├── sync_version │ │ └── index.rst │ ├── async_version │ │ └── index.rst │ ├── install.rst │ ├── locales │ │ ├── en │ │ │ └── LC_MESSAGES │ │ │ │ ├── quick_start.po │ │ │ │ ├── install.po │ │ │ │ ├── index.po │ │ │ │ └── calldata.po │ │ └── ru │ │ │ └── LC_MESSAGES │ │ │ ├── quick_start.po │ │ │ ├── install.po │ │ │ └── index.po │ ├── index.rst │ └── conf.py └── Makefile ├── doc_req.txt ├── examples ├── detailed_example │ ├── kitten.jpg │ └── rooster.jpg ├── multibot │ ├── nginx_conf.conf │ ├── config.py │ ├── handlers.py │ ├── README.MD │ └── main.py ├── asynchronous_telebot │ ├── multibot │ │ ├── nginx_conf.conf │ │ ├── config.py │ │ ├── handlers.py │ │ ├── README.MD │ │ └── main.py │ ├── chat_join_request.py │ ├── update_listener.py │ ├── custom_filters │ │ ├── admin_filter_example.py │ │ ├── id_filter_example.py │ │ ├── is_filter_example.py │ │ ├── text_filter_example.py │ │ └── general_custom_filters.py │ ├── skip_updates_example.py │ ├── register_handler.py │ ├── exception_handler.py │ ├── download_file_example.py │ ├── echo_bot.py │ ├── detect_changes.py │ ├── send_file_example.py │ ├── callback_data_examples │ │ ├── advanced_calendar_example │ │ │ ├── filters.py │ │ │ ├── main.py │ │ │ └── keyboards.py │ │ └── simple_products_example.py │ ├── continue_handling.py │ ├── middleware │ │ ├── i18n_middleware_example │ │ │ ├── keyboards.py │ │ │ └── locales │ │ │ │ ├── en │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── messages.po │ │ │ │ ├── uz_Latn │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── messages.po │ │ │ │ └── ru │ │ │ │ └── LC_MESSAGES │ │ │ │ └── messages.po │ │ ├── flooding_middleware.py │ │ └── i18n.py │ ├── set_command_example.py │ ├── timer_bot_async.py │ ├── webhooks │ │ ├── run_webhooks.py │ │ ├── webhook_starlette_echo_bot.py │ │ └── async_webhook_aiohttp_echo_bot.py │ ├── chat_member_example.py │ ├── formatting_example.py │ └── custom_states.py ├── chat_join_request.py ├── custom_filters │ ├── admin_filter_example.py │ ├── id_filter_example.py │ ├── is_filter_example.py │ ├── text_filter_example.py │ └── general_custom_filters.py ├── skip_updates_example.py ├── download_file_example.py ├── register_handler.py ├── middleware │ ├── function_based │ │ ├── i18n_gettext │ │ │ ├── keyboards.py │ │ │ ├── locales │ │ │ │ ├── en │ │ │ │ │ └── LC_MESSAGES │ │ │ │ │ │ └── messages.po │ │ │ │ ├── uz_Latn │ │ │ │ │ └── LC_MESSAGES │ │ │ │ │ │ └── messages.po │ │ │ │ └── ru │ │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── messages.po │ │ │ └── i18n_class.py │ │ ├── i18n.py │ │ └── session.py │ ├── class_based │ │ ├── i18n_middleware │ │ │ ├── keyboards.py │ │ │ └── locales │ │ │ │ ├── en │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── messages.po │ │ │ │ ├── uz_Latn │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── messages.po │ │ │ │ └── ru │ │ │ │ └── LC_MESSAGES │ │ │ │ └── messages.po │ │ ├── basic_example.py │ │ └── antiflood_middleware.py │ └── README.md ├── continue_handling.py ├── echo_bot.py ├── poll_example.py ├── detect_changes.py ├── callback_data_examples │ ├── advanced_calendar_example │ │ ├── filters.py │ │ ├── main.py │ │ └── keyboards.py │ └── simple_products_example.py ├── inline_keyboard_example.py ├── set_command_example.py ├── webhook_examples │ ├── webhook_flask_heroku_echo.py │ ├── run_webhooks.py │ ├── README.md │ ├── webhook_fastapi_echo_bot.py │ ├── webhook_aiohttp_echo_bot.py │ ├── webhook_flask_echo_bot.py │ ├── webhook_twisted_echo_bot.py │ ├── webhook_cherrypy_echo_bot.py │ ├── webhook_tornado_echo_bot.py │ └── webhook_cpython_echo_bot.py ├── timer_bot.py ├── serverless │ ├── aws_lambda_function.py │ └── azure_functions ├── create_invite_link.py ├── chat_member_example.py ├── formatting_example.py ├── step_example.py ├── inline_example.py ├── reply_keyboard_markup_example.py ├── deep_linking.py ├── telebot_bot │ └── telebot_bot.py └── custom_states.py ├── .github ├── ISSUE_TEMPLATE ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── setup_python.yml ├── .travis.yml ├── .readthedocs.yml ├── .gitignore └── setup.py /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | requests==2.20.0 3 | wheel==0.38.1 4 | aiohttp>=3.8.0,<3.9.0 -------------------------------------------------------------------------------- /telebot/ext/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A folder with asynchronous and synchronous extensions. 3 | """ 4 | -------------------------------------------------------------------------------- /tests/test_data/record.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/tests/test_data/record.mp3 -------------------------------------------------------------------------------- /tests/test_data/record.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/tests/test_data/record.ogg -------------------------------------------------------------------------------- /tests/test_data/record.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/tests/test_data/record.wav -------------------------------------------------------------------------------- /docs/source/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/docs/source/_static/logo.png -------------------------------------------------------------------------------- /docs/source/_static/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/docs/source/_static/logo2.png -------------------------------------------------------------------------------- /telebot/version.py: -------------------------------------------------------------------------------- 1 | # Versions should comply with PEP440. 2 | # This line is parsed in setup.py: 3 | __version__ = '4.10.0' 4 | -------------------------------------------------------------------------------- /doc_req.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | 3 | furo 4 | sphinx_copybutton 5 | git+https://github.com/eternnoir/pyTelegramBotAPI.git 6 | -------------------------------------------------------------------------------- /tests/test_data/test_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/tests/test_data/test_video.mp4 -------------------------------------------------------------------------------- /examples/detailed_example/kitten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/examples/detailed_example/kitten.jpg -------------------------------------------------------------------------------- /examples/detailed_example/rooster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislavkononiuk/pyTelegramBotAPI/HEAD/examples/detailed_example/rooster.jpg -------------------------------------------------------------------------------- /examples/multibot/nginx_conf.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name your_domain.com; 3 | 4 | location /telegram_webhook/ { 5 | proxy_pass http://localhost:3500; 6 | } 7 | 8 | } -------------------------------------------------------------------------------- /docs/source/types.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Types of API 3 | ============ 4 | 5 | 6 | 7 | .. automodule:: telebot.types 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /examples/multibot/config.py: -------------------------------------------------------------------------------- 1 | MAIN_BOT_TOKEN = "your_main_bot_token" 2 | 3 | WEBHOOK_HOST = "your_domain.com" 4 | WEBHOOK_PATH = "telegram_webhook" 5 | WEBAPP_HOST = "0.0.0.0" 6 | WEBAPP_PORT = 3500 7 | -------------------------------------------------------------------------------- /telebot/ext/aio/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A folder with all the async extensions. 3 | """ 4 | 5 | from .webhooks import AsyncWebhookListener 6 | 7 | 8 | __all__ = [ 9 | "AsyncWebhookListener" 10 | ] -------------------------------------------------------------------------------- /telebot/ext/sync/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A folder with all the sync extensions. 3 | """ 4 | 5 | from .webhooks import SyncWebhookListener 6 | 7 | 8 | __all__ = [ 9 | "SyncWebhookListener" 10 | ] -------------------------------------------------------------------------------- /examples/asynchronous_telebot/multibot/nginx_conf.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name your_domain.com; 3 | 4 | location /telegram_webhook/ { 5 | proxy_pass http://localhost:3500; 6 | } 7 | 8 | } -------------------------------------------------------------------------------- /examples/asynchronous_telebot/multibot/config.py: -------------------------------------------------------------------------------- 1 | MAIN_BOT_TOKEN = "your_main_bot_token" 2 | 3 | WEBHOOK_HOST = "your_domain.com" 4 | WEBHOOK_PATH = "telegram_webhook" 5 | WEBAPP_HOST = "0.0.0.0" 6 | WEBAPP_PORT = 3500 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | Please answer these questions before submitting your issue. Thanks! 2 | 3 | 1. What version of pyTelegramBotAPI are you using? 4 | 5 | 2. What OS are you using? 6 | 7 | 3. What version of python are you using? 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.7" 4 | - "3.8" 5 | - "3.9" 6 | - "3.10" 7 | - "3.11" 8 | - "pypy3" 9 | install: "pip install -r requirements.txt" 10 | script: 11 | - python setup.py install 12 | - cd tests && py.test 13 | -------------------------------------------------------------------------------- /docs/source/util.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Utils 3 | ============ 4 | 5 | .. meta:: 6 | :description: Utils in pyTelegramBotAPI 7 | :keywords: ptba, pytba, pyTelegramBotAPI, utils, guide 8 | 9 | 10 | util file 11 | ------------------- 12 | 13 | .. automodule:: telebot.util 14 | :members: 15 | :undoc-members: 16 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/formatting.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Formatting options 3 | ================== 4 | 5 | .. meta:: 6 | :description: Formatting options in pyTelegramBotAPI 7 | :keywords: html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI 8 | 9 | .. automodule:: telebot.formatting 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Include changes, new features and etc: 3 | 4 | ## Describe your tests 5 | How did you test your change? 6 | 7 | Python version: 8 | 9 | OS: 10 | 11 | ## Checklist: 12 | - [ ] I added/edited example on new feature/change (if exists) 13 | - [ ] My changes won't break backward compatibility 14 | - [ ] I made changes both for sync and async 15 | -------------------------------------------------------------------------------- /examples/chat_join_request.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | 3 | 4 | bot = telebot.TeleBot('TOKEN') 5 | 6 | @bot.chat_join_request_handler() 7 | def make_some(message: telebot.types.ChatJoinRequest): 8 | bot.send_message(message.chat.id, 'I accepted a new user!') 9 | bot.approve_chat_join_request(message.chat.id, message.from_user.id) 10 | 11 | bot.infinity_polling(allowed_updates=telebot.util.update_types) -------------------------------------------------------------------------------- /examples/custom_filters/admin_filter_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import custom_filters 3 | bot = telebot.TeleBot('TOKEN') 4 | 5 | # Handler 6 | @bot.message_handler(chat_types=['supergroup'], is_chat_admin=True) 7 | def answer_for_admin(message): 8 | bot.send_message(message.chat.id,"hello my admin") 9 | 10 | # Register filter 11 | bot.add_custom_filter(custom_filters.IsAdminFilter(bot)) 12 | bot.infinity_polling() 13 | -------------------------------------------------------------------------------- /examples/skip_updates_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | 3 | bot = telebot.TeleBot("TOKEN") 4 | 5 | @bot.message_handler(commands=['start', 'help']) 6 | def send_welcome(message): 7 | bot.reply_to(message, "Howdy, how are you doing?") 8 | 9 | @bot.message_handler(func=lambda message: True) 10 | def echo_all(message): 11 | bot.reply_to(message, message.text) 12 | 13 | bot.infinity_polling(skip_pending=True)# Skip pending skips old updates 14 | -------------------------------------------------------------------------------- /examples/download_file_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | 3 | TOKEN = 'YOUR BOT TOKEN' 4 | CHAT_ID = 'YOUR CHAT ID' 5 | 6 | bot = telebot.TeleBot(TOKEN) 7 | 8 | ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg', 'rb')) 9 | 10 | file_info = bot.get_file(ret_msg.voice.file_id) 11 | 12 | downloaded_file = bot.download_file(file_info.file_path) 13 | 14 | with open('new_file.ogg', 'wb') as new_file: 15 | new_file.write(downloaded_file) 16 | -------------------------------------------------------------------------------- /telebot/storage/__init__.py: -------------------------------------------------------------------------------- 1 | from telebot.storage.memory_storage import StateMemoryStorage 2 | from telebot.storage.redis_storage import StateRedisStorage 3 | from telebot.storage.pickle_storage import StatePickleStorage 4 | from telebot.storage.base_storage import StateContext,StateStorageBase 5 | 6 | 7 | 8 | 9 | 10 | __all__ = [ 11 | 'StateStorageBase', 'StateContext', 12 | 'StateMemoryStorage', 'StateRedisStorage', 'StatePickleStorage' 13 | ] -------------------------------------------------------------------------------- /docs/source/calldata.rst: -------------------------------------------------------------------------------- 1 | 2 | ===================== 3 | Callback data factory 4 | ===================== 5 | 6 | .. meta:: 7 | :description: Callback data factory in pyTelegramBotAPI 8 | :keywords: ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, factory 9 | 10 | 11 | callback\_data file 12 | ----------------------------- 13 | 14 | .. automodule:: telebot.callback_data 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: -------------------------------------------------------------------------------- /examples/asynchronous_telebot/chat_join_request.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | 3 | import telebot 4 | bot = AsyncTeleBot('TOKEN') 5 | 6 | @bot.chat_join_request_handler() 7 | async def make_some(message: telebot.types.ChatJoinRequest): 8 | await bot.send_message(message.chat.id, 'I accepted a new user!') 9 | await bot.approve_chat_join_request(message.chat.id, message.from_user.id) 10 | 11 | import asyncio 12 | asyncio.run(bot.polling()) -------------------------------------------------------------------------------- /telebot/asyncio_storage/__init__.py: -------------------------------------------------------------------------------- 1 | from telebot.asyncio_storage.memory_storage import StateMemoryStorage 2 | from telebot.asyncio_storage.redis_storage import StateRedisStorage 3 | from telebot.asyncio_storage.pickle_storage import StatePickleStorage 4 | from telebot.asyncio_storage.base_storage import StateContext,StateStorageBase 5 | 6 | 7 | 8 | 9 | 10 | __all__ = [ 11 | 'StateStorageBase', 'StateContext', 12 | 'StateMemoryStorage', 'StateRedisStorage', 'StatePickleStorage' 13 | ] -------------------------------------------------------------------------------- /docs/source/quick_start.rst: -------------------------------------------------------------------------------- 1 | 2 | =========== 3 | Quick start 4 | =========== 5 | 6 | .. meta:: 7 | :description: Quickstart guide 8 | :keywords: ptba, pytba, pyTelegramBotAPI, quickstart, guide 9 | 10 | Synchronous TeleBot 11 | ------------------- 12 | .. literalinclude:: ../../examples/echo_bot.py 13 | :language: python 14 | 15 | Asynchronous TeleBot 16 | -------------------- 17 | .. literalinclude:: ../../examples/asynchronous_telebot/echo_bot.py 18 | :language: python 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/update_listener.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | 3 | # Update listeners are functions that are called when any update is received. 4 | 5 | bot = AsyncTeleBot(token='TOKEN') 6 | 7 | async def update_listener(messages): 8 | for message in messages: 9 | if message.text == '/start': 10 | await bot.send_message(message.chat.id, 'Hello!') 11 | 12 | bot.set_update_listener(update_listener) 13 | 14 | 15 | import asyncio 16 | asyncio.run(bot.polling()) -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_filters/admin_filter_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot import asyncio_filters 3 | bot = AsyncTeleBot('TOKEN') 4 | 5 | # Handler 6 | @bot.message_handler(chat_types=['supergroup'], is_chat_admin=True) 7 | async def answer_for_admin(message): 8 | await bot.send_message(message.chat.id,"hello my admin") 9 | 10 | # Register filter 11 | bot.add_custom_filter(asyncio_filters.IsAdminFilter(bot)) 12 | 13 | import asyncio 14 | asyncio.run(bot.polling()) 15 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/skip_updates_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | 3 | bot = AsyncTeleBot('TOKEN') 4 | 5 | @bot.message_handler(commands=['start', 'help']) 6 | async def send_welcome(message): 7 | await bot.reply_to(message, "Howdy, how are you doing?") 8 | 9 | @bot.message_handler(func=lambda message: True) 10 | async def echo_all(message): 11 | await bot.reply_to(message, message.text) 12 | 13 | 14 | import asyncio 15 | asyncio.run(bot.polling(skip_pending=True)) # to skip updates 16 | -------------------------------------------------------------------------------- /examples/multibot/handlers.py: -------------------------------------------------------------------------------- 1 | from telebot import types, TeleBot 2 | 3 | 4 | def hello_handler(message: types.Message, bot: TeleBot): 5 | bot.send_message(message.chat.id, "Hi :)") 6 | 7 | 8 | def echo_handler(message: types.Message, bot: TeleBot): 9 | bot.send_message(message.chat.id, message.text) 10 | 11 | 12 | def register_handlers(bot: TeleBot): 13 | bot.register_message_handler(hello_handler, func=lambda message: message.text == 'Hello', pass_bot=True) 14 | bot.register_message_handler(echo_handler, pass_bot=True) 15 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/source/conf.py 11 | 12 | # Optionally build your docs in additional formats such as PDF and ePub 13 | formats: all 14 | 15 | # Optionally set the version of Python and requirements required to build your docs 16 | python: 17 | version: 3.7 18 | install: 19 | - requirements: doc_req.txt -------------------------------------------------------------------------------- /examples/asynchronous_telebot/multibot/handlers.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot import types 3 | 4 | 5 | async def hello_handler(message: types.Message, bot: AsyncTeleBot): 6 | await bot.send_message(message.chat.id, "Hi :)") 7 | 8 | 9 | async def echo_handler(message: types.Message, bot: AsyncTeleBot): 10 | await bot.send_message(message.chat.id, message.text) 11 | 12 | 13 | def register_handlers(bot: AsyncTeleBot): 14 | bot.register_message_handler(hello_handler, func=lambda message: message.text == 'Hello', pass_bot=True) 15 | bot.register_message_handler(echo_handler, pass_bot=True) 16 | -------------------------------------------------------------------------------- /examples/custom_filters/id_filter_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import custom_filters 3 | 4 | bot = telebot.TeleBot('token') 5 | 6 | 7 | # Chat id can be private or supergroups. 8 | @bot.message_handler(chat_id=[12345678], commands=['admin']) # chat_id checks id corresponds to your list or not. 9 | def admin_rep(message): 10 | bot.send_message(message.chat.id, "You are allowed to use this command.") 11 | 12 | @bot.message_handler(commands=['admin']) 13 | def not_admin(message): 14 | bot.send_message(message.chat.id, "You are not allowed to use this command") 15 | 16 | # Do not forget to register 17 | bot.add_custom_filter(custom_filters.ChatFilter()) 18 | 19 | bot.infinity_polling() 20 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /examples/custom_filters/is_filter_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import custom_filters 3 | 4 | bot = telebot.TeleBot('TOKEN') 5 | 6 | 7 | # Check if message is a reply 8 | @bot.message_handler(is_reply=True) 9 | def start_filter(message): 10 | bot.send_message(message.chat.id, "Looks like you replied to my message.") 11 | 12 | # Check if message was forwarded 13 | @bot.message_handler(is_forwarded=True) 14 | def text_filter(message): 15 | bot.send_message(message.chat.id, "I do not accept forwarded messages!") 16 | 17 | # Do not forget to register filters 18 | bot.add_custom_filter(custom_filters.IsReplyFilter()) 19 | bot.add_custom_filter(custom_filters.ForwardFilter()) 20 | 21 | bot.infinity_polling() 22 | -------------------------------------------------------------------------------- /examples/register_handler.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | 3 | api_token = 'token' 4 | 5 | bot = telebot.TeleBot(api_token) 6 | 7 | def start_executor(message): 8 | bot.send_message(message.chat.id, 'Hello!') 9 | 10 | bot.register_message_handler(start_executor, commands=['start']) # Start command executor 11 | 12 | # See also 13 | # bot.register_callback_query_handler(*args, **kwargs) 14 | # bot.register_channel_post_handler(*args, **kwargs) 15 | # bot.register_chat_member_handler(*args, **kwargs) 16 | # bot.register_inline_handler(*args, **kwargs) 17 | # bot.register_my_chat_member_handler(*args, **kwargs) 18 | # bot.register_edited_message_handler(*args, **kwargs) 19 | # And other functions.. 20 | 21 | bot.infinity_polling() 22 | -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n_gettext/keyboards.py: -------------------------------------------------------------------------------- 1 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton 2 | 3 | 4 | def languages_keyboard(): 5 | return InlineKeyboardMarkup( 6 | keyboard=[ 7 | [ 8 | InlineKeyboardButton(text="English", callback_data='en'), 9 | InlineKeyboardButton(text="Русский", callback_data='ru'), 10 | InlineKeyboardButton(text="O'zbekcha", callback_data='uz_Latn') 11 | ] 12 | ] 13 | ) 14 | 15 | 16 | def clicker_keyboard(_): 17 | return InlineKeyboardMarkup( 18 | keyboard=[ 19 | [ 20 | InlineKeyboardButton(text=_("click"), callback_data='click'), 21 | ] 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/register_handler.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | bot = AsyncTeleBot('TOKEN') 3 | 4 | async def start_executor(message): 5 | await bot.send_message(message.chat.id, 'Hello!') 6 | 7 | bot.register_message_handler(start_executor, commands=['start']) # Start command executor 8 | 9 | # See also 10 | # bot.register_callback_query_handler(*args, **kwargs) 11 | # bot.register_channel_post_handler(*args, **kwargs) 12 | # bot.register_chat_member_handler(*args, **kwargs) 13 | # bot.register_inline_handler(*args, **kwargs) 14 | # bot.register_my_chat_member_handler(*args, **kwargs) 15 | # bot.register_edited_message_handler(*args, **kwargs) 16 | # And other functions.. 17 | 18 | 19 | import asyncio 20 | asyncio.run(bot.polling()) 21 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_filters/id_filter_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | import telebot 3 | bot = AsyncTeleBot('TOKEN') 4 | 5 | 6 | # Chat id can be private or supergroups. 7 | @bot.message_handler(chat_id=[12345678], commands=['admin']) # chat_id checks id corresponds to your list or not. 8 | async def admin_rep(message): 9 | await bot.send_message(message.chat.id, "You are allowed to use this command.") 10 | 11 | @bot.message_handler(commands=['admin']) 12 | async def not_admin(message): 13 | await bot.send_message(message.chat.id, "You are not allowed to use this command") 14 | 15 | # Do not forget to register 16 | bot.add_custom_filter(telebot.asyncio_filters.ChatFilter()) 17 | import asyncio 18 | asyncio.run(bot.polling()) 19 | -------------------------------------------------------------------------------- /examples/custom_filters/text_filter_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import custom_filters 3 | 4 | bot = telebot.TeleBot('TOKEN') 5 | 6 | 7 | # Check if message starts with @admin tag 8 | @bot.message_handler(text_startswith="@admin") 9 | def start_filter(message): 10 | bot.send_message(message.chat.id, "Looks like you are calling admin, wait...") 11 | 12 | # Check if text is hi or hello 13 | @bot.message_handler(text=['hi','hello']) 14 | def text_filter(message): 15 | bot.send_message(message.chat.id, "Hi, {name}!".format(name=message.from_user.first_name)) 16 | 17 | # Do not forget to register filters 18 | bot.add_custom_filter(custom_filters.TextMatchFilter()) 19 | bot.add_custom_filter(custom_filters.TextStartsFilter()) 20 | 21 | bot.infinity_polling() 22 | -------------------------------------------------------------------------------- /examples/continue_handling.py: -------------------------------------------------------------------------------- 1 | from telebot import TeleBot 2 | from telebot.handler_backends import ContinueHandling 3 | 4 | 5 | bot = TeleBot('TOKEN') 6 | 7 | @bot.message_handler(commands=['start']) 8 | def start(message): 9 | bot.send_message(message.chat.id, 'Hello World!') 10 | return ContinueHandling() 11 | 12 | @bot.message_handler(commands=['start']) 13 | def start2(message): 14 | """ 15 | This handler comes after the first one, but it will never be called. 16 | But you can call it by returning ContinueHandling() in the first handler. 17 | 18 | If you return ContinueHandling() in the first handler, the next 19 | registered handler with appropriate filters will be called. 20 | """ 21 | bot.send_message(message.chat.id, 'Hello World2!') 22 | 23 | bot.infinity_polling() 24 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_filters/is_filter_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | import telebot 3 | 4 | bot = AsyncTeleBot('TOKEN') 5 | 6 | 7 | 8 | # Check if message is a reply 9 | @bot.message_handler(is_reply=True) 10 | async def start_filter(message): 11 | await bot.send_message(message.chat.id, "Looks like you replied to my message.") 12 | 13 | # Check if message was forwarded 14 | @bot.message_handler(is_forwarded=True) 15 | async def text_filter(message): 16 | await bot.send_message(message.chat.id, "I do not accept forwarded messages!") 17 | 18 | # Do not forget to register filters 19 | bot.add_custom_filter(telebot.asyncio_filters.IsReplyFilter()) 20 | bot.add_custom_filter(telebot.asyncio_filters.ForwardFilter()) 21 | 22 | import asyncio 23 | asyncio.run(bot.polling()) 24 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/exception_handler.py: -------------------------------------------------------------------------------- 1 | 2 | import telebot 3 | from telebot.async_telebot import AsyncTeleBot 4 | 5 | 6 | import logging 7 | 8 | logger = telebot.logger 9 | telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. 10 | 11 | class ExceptionHandler(telebot.ExceptionHandler): 12 | def handle(self, exception): 13 | logger.error(exception) 14 | 15 | bot = AsyncTeleBot('TOKEN',exception_handler=ExceptionHandler()) 16 | 17 | 18 | 19 | 20 | @bot.message_handler(commands=['photo']) 21 | async def photo_send(message: telebot.types.Message): 22 | await bot.send_message(message.chat.id, 'Hi, this is an example of exception handlers.') 23 | raise Exception('test') # Exception goes to ExceptionHandler if it is set 24 | 25 | 26 | 27 | import asyncio 28 | asyncio.run(bot.polling()) 29 | -------------------------------------------------------------------------------- /examples/echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | 6 | import telebot 7 | 8 | API_TOKEN = '' 9 | 10 | bot = telebot.TeleBot(API_TOKEN) 11 | 12 | 13 | # Handle '/start' and '/help' 14 | @bot.message_handler(commands=['help', 'start']) 15 | def send_welcome(message): 16 | bot.reply_to(message, """\ 17 | Hi there, I am EchoBot. 18 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 19 | """) 20 | 21 | 22 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 23 | @bot.message_handler(func=lambda message: True) 24 | def echo_message(message): 25 | bot.reply_to(message, message.text) 26 | 27 | 28 | bot.infinity_polling() 29 | -------------------------------------------------------------------------------- /examples/poll_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is an example file to create quiz polls 4 | import telebot 5 | 6 | API_TOKEN = "" 7 | 8 | bot = telebot.TeleBot(API_TOKEN) 9 | 10 | 11 | @bot.message_handler(commands=["poll"]) 12 | def create_poll(message): 13 | bot.send_message(message.chat.id, "English Article Test") 14 | answer_options = ["a", "an", "the", "-"] 15 | 16 | bot.send_poll( 17 | chat_id=message.chat.id, 18 | question="We are going to '' park.", 19 | options=answer_options, 20 | type="quiz", 21 | correct_option_id=2, 22 | is_anonymous=False, 23 | ) 24 | 25 | 26 | @bot.poll_answer_handler() 27 | def handle_poll(poll): 28 | # This handler can be used to log User answers and to send next poll 29 | pass 30 | 31 | 32 | bot.infinity_polling() 33 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/download_file_example.py: -------------------------------------------------------------------------------- 1 | 2 | import telebot 3 | from telebot.async_telebot import AsyncTeleBot 4 | 5 | 6 | 7 | bot = AsyncTeleBot('TOKEN') 8 | 9 | 10 | @bot.message_handler(content_types=['photo']) 11 | async def new_message(message: telebot.types.Message): 12 | result_message = await bot.send_message(message.chat.id, 'Downloading your photo...', parse_mode='HTML', disable_web_page_preview=True) 13 | file_path = await bot.get_file(message.photo[-1].file_id) 14 | downloaded_file = await bot.download_file(file_path.file_path) 15 | with open('file.jpg', 'wb') as new_file: 16 | new_file.write(downloaded_file) 17 | await bot.edit_message_text(chat_id=message.chat.id, message_id=result_message.id, text='Done!', parse_mode='HTML') 18 | 19 | 20 | import asyncio 21 | asyncio.run(bot.polling()) 22 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_filters/text_filter_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | import telebot 3 | bot = AsyncTeleBot('TOKEN') 4 | 5 | 6 | # Check if message starts with @admin tag 7 | @bot.message_handler(text_startswith="@admin") 8 | async def start_filter(message): 9 | await bot.send_message(message.chat.id, "Looks like you are calling admin, wait...") 10 | 11 | # Check if text is hi or hello 12 | @bot.message_handler(text=['hi','hello']) 13 | async def text_filter(message): 14 | await bot.send_message(message.chat.id, "Hi, {name}!".format(name=message.from_user.first_name)) 15 | 16 | # Do not forget to register filters 17 | bot.add_custom_filter(telebot.asyncio_filters.TextMatchFilter()) 18 | bot.add_custom_filter(telebot.asyncio_filters.TextStartsFilter()) 19 | 20 | import asyncio 21 | asyncio.run(bot.polling()) 22 | -------------------------------------------------------------------------------- /examples/detect_changes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | 6 | import telebot 7 | 8 | API_TOKEN = '' 9 | 10 | bot = telebot.TeleBot(API_TOKEN) 11 | 12 | 13 | # Handle '/start' and '/help' 14 | @bot.message_handler(commands=['help', 'start']) 15 | def send_welcome(message): 16 | bot.reply_to(message, """\ 17 | Hi there, I am EchoBot. 18 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 19 | """) 20 | 21 | 22 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 23 | @bot.message_handler(func=lambda message: True) 24 | def echo_message(message): 25 | bot.reply_to(message, message.text) 26 | 27 | # only for versions 4.7.0+ 28 | bot.infinity_polling(restart_on_change=True) 29 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | 6 | from telebot.async_telebot import AsyncTeleBot 7 | bot = AsyncTeleBot('TOKEN') 8 | 9 | 10 | 11 | # Handle '/start' and '/help' 12 | @bot.message_handler(commands=['help', 'start']) 13 | async def send_welcome(message): 14 | await bot.reply_to(message, """\ 15 | Hi there, I am EchoBot. 16 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 17 | """) 18 | 19 | 20 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 21 | @bot.message_handler(func=lambda message: True) 22 | async def echo_message(message): 23 | await bot.reply_to(message, message.text) 24 | 25 | 26 | import asyncio 27 | asyncio.run(bot.polling()) 28 | -------------------------------------------------------------------------------- /docs/source/sync_version/index.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | TeleBot version 3 | =============== 4 | 5 | .. meta:: 6 | :description: Synchronous pyTelegramBotAPI documentation 7 | :keywords: ptba, pytba, pyTelegramBotAPI, methods, guide, files, sync 8 | 9 | TeleBot methods 10 | --------------- 11 | .. automodule:: telebot 12 | :members: 13 | :undoc-members: 14 | :show-inheritance: 15 | 16 | custom_filters file 17 | ------------------------------ 18 | 19 | .. automodule:: telebot.custom_filters 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | handler_backends file 25 | -------------------------------- 26 | 27 | .. automodule:: telebot.handler_backends 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | 32 | 33 | Extensions 34 | ------------------------ 35 | 36 | 37 | 38 | .. automodule:: telebot.ext.sync.webhooks 39 | :members: 40 | :undoc-members: 41 | :show-inheritance: -------------------------------------------------------------------------------- /telebot/ext/reloader.py: -------------------------------------------------------------------------------- 1 | 2 | from watchdog.events import FileSystemEventHandler 3 | from watchdog.events import FileSystemEvent 4 | import psutil 5 | import os 6 | import sys 7 | import logging 8 | 9 | logger = logging.getLogger('TeleBot') 10 | 11 | class EventHandler(FileSystemEventHandler): 12 | def on_any_event(self, event: FileSystemEvent): 13 | logger.info('* Detected changes in: %s, reloading', (event.src_path)) 14 | restart_file() 15 | 16 | def restart_file(): 17 | try: 18 | p = psutil.Process(os.getpid()) 19 | for handler in p.open_files() + p.connections(): 20 | os.close(handler.fd) 21 | except OSError: 22 | pass 23 | except Exception as e: 24 | logger.error(e) 25 | 26 | python = sys.executable 27 | 28 | if os.name == 'nt': 29 | os.execv(sys.executable, ['python'] + sys.argv) 30 | else: 31 | os.execl(python, python, *sys.argv) 32 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/detect_changes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | 6 | from telebot.async_telebot import AsyncTeleBot 7 | bot = AsyncTeleBot('TOKEN') 8 | 9 | 10 | 11 | # Handle '/start' and '/help' 12 | @bot.message_handler(commands=['help', 'start']) 13 | async def send_welcome(message): 14 | await bot.reply_to(message, """\ 15 | Hi there, I am EchoBot. 16 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 17 | """) 18 | 19 | 20 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 21 | @bot.message_handler(func=lambda message: True) 22 | async def echo_message(message): 23 | await bot.reply_to(message, message.text) 24 | 25 | 26 | import asyncio 27 | # only for versions 4.7.0+ 28 | asyncio.run(bot.polling(restart_on_change=True)) 29 | -------------------------------------------------------------------------------- /examples/callback_data_examples/advanced_calendar_example/filters.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import types, AdvancedCustomFilter 3 | from telebot.callback_data import CallbackData, CallbackDataFilter 4 | 5 | calendar_factory = CallbackData("year", "month", prefix="calendar") 6 | calendar_zoom = CallbackData("year", prefix="calendar_zoom") 7 | 8 | 9 | class CalendarCallbackFilter(AdvancedCustomFilter): 10 | key = 'calendar_config' 11 | 12 | def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 13 | return config.check(query=call) 14 | 15 | 16 | class CalendarZoomCallbackFilter(AdvancedCustomFilter): 17 | key = 'calendar_zoom_config' 18 | 19 | def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 20 | return config.check(query=call) 21 | 22 | 23 | def bind_filters(bot: telebot.TeleBot): 24 | bot.add_custom_filter(CalendarCallbackFilter()) 25 | bot.add_custom_filter(CalendarZoomCallbackFilter()) 26 | -------------------------------------------------------------------------------- /examples/multibot/README.MD: -------------------------------------------------------------------------------- 1 | You probably have seen bots which allow you to send them token of your bot and then handle updates providing some functionality for your bot. 2 |
3 | This type of bots are called multibots. They are created using webhooks. 4 |
5 | 6 | This is the example of simple multibot.
7 | In order to reproduce this example you need to have domain and ssl connection. 8 |
9 | If you have, go to config.py and specify your data. 10 |
11 | There is also file called nginx_conf.conf, we will use nginx as proxy-server and this file is example nginx.conf file. 12 |
13 | Make sure that server_name and port are the same in both config and nginx_conf 14 |
15 | (nginx_conf.conf IS NOT complete, you would probably use tools like certbot to add ssl connection to it) 16 |
17 | Also, in this example I used dictionary as tokens storage, but in production you should use database so that you can re-set webhooks in case bot restarts. -------------------------------------------------------------------------------- /docs/source/async_version/index.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | AsyncTeleBot 3 | ==================== 4 | 5 | 6 | .. meta:: 7 | :description: Asynchronous pyTelegramBotAPI 8 | :keywords: ptba, pytba, pyTelegramBotAPI, asynctelebot, documentation 9 | 10 | 11 | AsyncTeleBot methods 12 | -------------------- 13 | 14 | .. automodule:: telebot.async_telebot 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | 21 | Asyncio filters 22 | --------------- 23 | 24 | .. automodule:: telebot.asyncio_filters 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | Asyncio handler backends 30 | ------------------------ 31 | 32 | 33 | 34 | .. automodule:: telebot.asyncio_handler_backends 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | 40 | Extensions 41 | ------------------------ 42 | 43 | 44 | 45 | .. automodule:: telebot.ext.aio.webhooks 46 | :members: 47 | :undoc-members: 48 | :show-inheritance: 49 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/multibot/README.MD: -------------------------------------------------------------------------------- 1 | You probably have seen bots which allow you to send them token of your bot and then handle updates providing some functionality for your bot. 2 |
3 | This type of bots are called multibots. They are created using webhooks. 4 |
5 | 6 | This is the example of simple multibot.
7 | In order to reproduce this example you need to have domain and ssl connection. 8 |
9 | If you have, go to config.py and specify your data. 10 |
11 | There is also file called nginx_conf.conf, we will use nginx as proxy-server and this file is example nginx.conf file. 12 |
13 | Make sure that server_name and port are the same in both config and nginx_conf 14 |
15 | (nginx_conf.conf IS NOT complete, you would probably use tools like certbot to add ssl connection to it) 16 |
17 | Also, in this example I used dictionary as tokens storage, but in production you should use database so that you can re-set webhooks in case bot restarts. -------------------------------------------------------------------------------- /examples/asynchronous_telebot/send_file_example.py: -------------------------------------------------------------------------------- 1 | 2 | import telebot 3 | from telebot.async_telebot import AsyncTeleBot 4 | 5 | 6 | 7 | bot = AsyncTeleBot('TOKEN') 8 | 9 | 10 | @bot.message_handler(commands=['photo']) 11 | async def photo_send(message: telebot.types.Message): 12 | with open('test.png', 'rb') as new_file: 13 | await bot.send_photo(message.chat.id, new_file) 14 | 15 | @bot.message_handler(commands=['document']) 16 | async def document_send(message: telebot.types.Message): 17 | with open('test.docx', 'rb') as new_file: 18 | await bot.send_document(message.chat.id, new_file) 19 | 20 | @bot.message_handler(commands=['photos']) 21 | async def photos_send(message: telebot.types.Message): 22 | with open('test.png', 'rb') as new_file, open('test2.png', 'rb') as new_file2: 23 | await bot.send_media_group(message.chat.id, [telebot.types.InputMediaPhoto(new_file), telebot.types.InputMediaPhoto(new_file2)]) 24 | 25 | 26 | 27 | 28 | import asyncio 29 | asyncio.run(bot.polling()) 30 | -------------------------------------------------------------------------------- /examples/inline_keyboard_example.py: -------------------------------------------------------------------------------- 1 | # This example show how to use inline keyboards and process button presses 2 | import telebot 3 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton 4 | 5 | TELEGRAM_TOKEN = '' 6 | 7 | bot = telebot.TeleBot(TELEGRAM_TOKEN) 8 | 9 | def gen_markup(): 10 | markup = InlineKeyboardMarkup() 11 | markup.row_width = 2 12 | markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"), 13 | InlineKeyboardButton("No", callback_data="cb_no")) 14 | return markup 15 | 16 | @bot.callback_query_handler(func=lambda call: True) 17 | def callback_query(call): 18 | if call.data == "cb_yes": 19 | bot.answer_callback_query(call.id, "Answer is Yes") 20 | elif call.data == "cb_no": 21 | bot.answer_callback_query(call.id, "Answer is No") 22 | 23 | @bot.message_handler(func=lambda message: True) 24 | def message_handler(message): 25 | bot.send_message(message.chat.id, "Yes/no?", reply_markup=gen_markup()) 26 | 27 | bot.infinity_polling() 28 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/callback_data_examples/advanced_calendar_example/filters.py: -------------------------------------------------------------------------------- 1 | from telebot import types 2 | from telebot.async_telebot import AsyncTeleBot 3 | from telebot.asyncio_filters import AdvancedCustomFilter 4 | from telebot.callback_data import CallbackData, CallbackDataFilter 5 | 6 | calendar_factory = CallbackData("year", "month", prefix="calendar") 7 | calendar_zoom = CallbackData("year", prefix="calendar_zoom") 8 | 9 | 10 | class CalendarCallbackFilter(AdvancedCustomFilter): 11 | key = 'calendar_config' 12 | 13 | async def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 14 | return config.check(query=call) 15 | 16 | 17 | class CalendarZoomCallbackFilter(AdvancedCustomFilter): 18 | key = 'calendar_zoom_config' 19 | 20 | async def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 21 | return config.check(query=call) 22 | 23 | 24 | def bind_filters(bot: AsyncTeleBot): 25 | bot.add_custom_filter(CalendarCallbackFilter()) 26 | bot.add_custom_filter(CalendarZoomCallbackFilter()) 27 | -------------------------------------------------------------------------------- /examples/set_command_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a set_my_commands example. 4 | # Press on [/] button in telegram client. 5 | # Important, to update the command menu, be sure to exit the chat with the bot and enter to chat again 6 | # Important, command for chat_id and for group have a higher priority than for all 7 | 8 | import telebot 9 | 10 | 11 | API_TOKEN = '' 12 | bot = telebot.TeleBot(API_TOKEN) 13 | 14 | # use in for delete with the necessary scope and language_code if necessary 15 | bot.delete_my_commands(scope=None, language_code=None) 16 | 17 | bot.set_my_commands( 18 | commands=[ 19 | telebot.types.BotCommand("command1", "command1 description"), 20 | telebot.types.BotCommand("command2", "command2 description") 21 | ], 22 | # scope=telebot.types.BotCommandScopeChat(12345678) # use for personal command for users 23 | # scope=telebot.types.BotCommandScopeAllPrivateChats() # use for all private chats 24 | ) 25 | 26 | # check command 27 | cmd = bot.get_my_commands(scope=None, language_code=None) 28 | print([c.to_json() for c in cmd]) 29 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/continue_handling.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot.asyncio_handler_backends import ContinueHandling 3 | 4 | 5 | bot = AsyncTeleBot('TOKEN') 6 | 7 | @bot.message_handler(commands=['start']) 8 | async def start(message): 9 | await bot.send_message(message.chat.id, 'Hello World!') 10 | return ContinueHandling() 11 | 12 | @bot.message_handler(commands=['start']) 13 | async def start2(message): 14 | """ 15 | This handler comes after the first one, but it will never be called. 16 | But you can call it by returning ContinueHandling() in the first handler. 17 | 18 | If you return ContinueHandling() in the first handler, the next 19 | registered handler with appropriate filters will be called. 20 | """ 21 | await bot.send_message(message.chat.id, 'Hello World2!') 22 | 23 | import asyncio 24 | asyncio.run(bot.polling()) # just a reminder that infinity polling 25 | # wraps polling into try/except block just as sync version, 26 | # but you can use any of them because neither of them stops if you 27 | # pass non_stop=True 28 | -------------------------------------------------------------------------------- /examples/middleware/class_based/i18n_middleware/keyboards.py: -------------------------------------------------------------------------------- 1 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton 2 | 3 | 4 | def languages_keyboard(): 5 | return InlineKeyboardMarkup( 6 | keyboard=[ 7 | [ 8 | InlineKeyboardButton(text="English", callback_data='en'), 9 | InlineKeyboardButton(text="Русский", callback_data='ru'), 10 | InlineKeyboardButton(text="O'zbekcha", callback_data='uz_Latn') 11 | ] 12 | ] 13 | ) 14 | 15 | 16 | def clicker_keyboard(_): 17 | return InlineKeyboardMarkup( 18 | keyboard=[ 19 | [ 20 | InlineKeyboardButton(text=_("click"), callback_data='click'), 21 | ] 22 | ] 23 | ) 24 | 25 | 26 | def menu_keyboard(_): 27 | keyboard = ReplyKeyboardMarkup(resize_keyboard=True) 28 | keyboard.add( 29 | KeyboardButton(text=_("My user id")), 30 | KeyboardButton(text=_("My user name")), 31 | KeyboardButton(text=_("My first name")) 32 | ) 33 | 34 | return keyboard 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | .idea/ 27 | venv/ 28 | .venv/ 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *,cover 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | 57 | # Sphinx documentation 58 | docs/_build/ 59 | 60 | # PyBuilder 61 | target/ 62 | testMain.py 63 | 64 | #VS Code 65 | .vscode/ 66 | .DS_Store 67 | *.code-workspace 68 | 69 | # documentation 70 | _build/ 71 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_flask_heroku_echo.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, request 4 | 5 | import telebot 6 | 7 | TOKEN = '' 8 | bot = telebot.TeleBot(TOKEN) 9 | server = Flask(__name__) 10 | 11 | 12 | @bot.message_handler(commands=['start']) 13 | def start(message): 14 | bot.reply_to(message, 'Hello, ' + message.from_user.first_name) 15 | 16 | 17 | @bot.message_handler(func=lambda message: True, content_types=['text']) 18 | def echo_message(message): 19 | bot.reply_to(message, message.text) 20 | 21 | 22 | @server.route('/' + TOKEN, methods=['POST']) 23 | def getMessage(): 24 | json_string = request.get_data().decode('utf-8') 25 | update = telebot.types.Update.de_json(json_string) 26 | bot.process_new_updates([update]) 27 | return "!", 200 28 | 29 | 30 | @server.route("/") 31 | def webhook(): 32 | bot.remove_webhook() 33 | bot.set_webhook(url='https://your_heroku_project.com/' + TOKEN) 34 | return "!", 200 35 | 36 | 37 | if __name__ == "__main__": 38 | server.run(host="0.0.0.0", port=int(os.environ.get('PORT', 5000))) 39 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/i18n_middleware_example/keyboards.py: -------------------------------------------------------------------------------- 1 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton 2 | 3 | 4 | def languages_keyboard(): 5 | return InlineKeyboardMarkup( 6 | keyboard=[ 7 | [ 8 | InlineKeyboardButton(text="English", callback_data='en'), 9 | InlineKeyboardButton(text="Русский", callback_data='ru'), 10 | InlineKeyboardButton(text="O'zbekcha", callback_data='uz_Latn') 11 | ] 12 | ] 13 | ) 14 | 15 | 16 | def clicker_keyboard(_): 17 | return InlineKeyboardMarkup( 18 | keyboard=[ 19 | [ 20 | InlineKeyboardButton(text=_("click"), callback_data='click'), 21 | ] 22 | ] 23 | ) 24 | 25 | 26 | def menu_keyboard(_): 27 | keyboard = ReplyKeyboardMarkup(resize_keyboard=True) 28 | keyboard.add( 29 | KeyboardButton(text=_("My user id")), 30 | KeyboardButton(text=_("My user name")), 31 | KeyboardButton(text=_("My first name")) 32 | ) 33 | 34 | return keyboard 35 | -------------------------------------------------------------------------------- /docs/source/install.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Installation Guide 3 | ================== 4 | 5 | .. meta:: 6 | :description: Installation of pyTelegramBotAPI 7 | :keywords: ptba, pytba, pyTelegramBotAPI, installation, guide 8 | 9 | 10 | Using PIP 11 | ---------- 12 | .. code-block:: bash 13 | 14 | $ pip install pyTelegramBotAPI 15 | 16 | Using pipenv 17 | ------------ 18 | .. code-block:: bash 19 | 20 | $ pipenv install pyTelegramBotAPI 21 | 22 | By cloning repository 23 | --------------------- 24 | .. code-block:: bash 25 | 26 | $ git clone https://github.com/eternnoir/pyTelegramBotAPI.git 27 | $ cd pyTelegramBotAPI 28 | $ python setup.py install 29 | 30 | Directly using pip 31 | ------------------ 32 | .. code-block:: bash 33 | 34 | $ pip install git+https://github.com/eternnoir/pyTelegramBotAPI.git 35 | 36 | 37 | It is generally recommended to use the first option. 38 | 39 | While the API is production-ready, it is still under development and it has regular updates, do not forget to update it regularly by calling: 40 | 41 | .. code-block:: bash 42 | 43 | $ pip install pytelegrambotapi --upgrade 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/source/locales/en/LC_MESSAGES/quick_start.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../quick_start.rst:4 22 | msgid "Quick start" 23 | msgstr "" 24 | 25 | #: ../../quick_start.rst:6 26 | msgid "Quickstart guide" 27 | msgstr "" 28 | 29 | #: ../../quick_start.rst:6 30 | msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide" 31 | msgstr "" 32 | 33 | #: ../../quick_start.rst:11 34 | msgid "Synchronous TeleBot" 35 | msgstr "" 36 | 37 | #: ../../quick_start.rst:16 38 | msgid "Asynchronous TeleBot" 39 | msgstr "" 40 | 41 | -------------------------------------------------------------------------------- /.github/workflows/setup_python.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Setup 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | #workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | all-setups: 20 | runs-on: ubuntu-latest 21 | strategy: 22 | matrix: 23 | python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9'] 24 | name: ${{ matrix.python-version }} and tests 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Setup python 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | architecture: x64 32 | - run: | 33 | pip3 install -r requirements.txt 34 | python setup.py install 35 | cd tests && py.test 36 | -------------------------------------------------------------------------------- /examples/timer_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple bot with schedule timer 4 | # https://schedule.readthedocs.io 5 | 6 | import time, threading, schedule 7 | from telebot import TeleBot 8 | 9 | API_TOKEN = '' 10 | bot = TeleBot(API_TOKEN) 11 | 12 | 13 | @bot.message_handler(commands=['help', 'start']) 14 | def send_welcome(message): 15 | bot.reply_to(message, "Hi! Use /set to set a timer") 16 | 17 | 18 | def beep(chat_id) -> None: 19 | """Send the beep message.""" 20 | bot.send_message(chat_id, text='Beep!') 21 | 22 | 23 | @bot.message_handler(commands=['set']) 24 | def set_timer(message): 25 | args = message.text.split() 26 | if len(args) > 1 and args[1].isdigit(): 27 | sec = int(args[1]) 28 | schedule.every(sec).seconds.do(beep, message.chat.id).tag(message.chat.id) 29 | else: 30 | bot.reply_to(message, 'Usage: /set ') 31 | 32 | 33 | @bot.message_handler(commands=['unset']) 34 | def unset_timer(message): 35 | schedule.clear(message.chat.id) 36 | 37 | 38 | if __name__ == '__main__': 39 | threading.Thread(target=bot.infinity_polling, name='bot_infinity_polling', daemon=True).start() 40 | while True: 41 | schedule.run_pending() 42 | time.sleep(1) 43 | -------------------------------------------------------------------------------- /docs/source/locales/ru/LC_MESSAGES/quick_start.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../quick_start.rst:4 22 | msgid "Quick start" 23 | msgstr "Быстрый старт" 24 | 25 | #: ../../quick_start.rst:6 26 | msgid "Quickstart guide" 27 | msgstr "Быстрый старт - гайд" 28 | 29 | #: ../../quick_start.rst:6 30 | msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide" 31 | msgstr "ptba, pytba, pyTelegramBotAPI, быстрый старт, гайд" 32 | 33 | #: ../../quick_start.rst:11 34 | msgid "Synchronous TeleBot" 35 | msgstr "Синхронный телебот" 36 | 37 | #: ../../quick_start.rst:16 38 | msgid "Asynchronous TeleBot" 39 | msgstr "Асинхронный телебот" 40 | 41 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/set_command_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a set_my_commands example. 4 | # Press on [/] button in telegram client. 5 | # Important, to update the command menu, be sure to exit the chat with the bot and log in again 6 | # Important, command for chat_id and for group have a higher priority than for all 7 | 8 | import asyncio 9 | import telebot 10 | from telebot.async_telebot import AsyncTeleBot 11 | 12 | 13 | API_TOKEN = '' 14 | bot = AsyncTeleBot(API_TOKEN) 15 | 16 | 17 | async def main(): 18 | # use in for delete with the necessary scope and language_code if necessary 19 | await bot.delete_my_commands(scope=None, language_code=None) 20 | 21 | await bot.set_my_commands( 22 | commands=[ 23 | telebot.types.BotCommand("command1", "command1 description"), 24 | telebot.types.BotCommand("command2", "command2 description") 25 | ], 26 | # scope=telebot.types.BotCommandScopeChat(12345678) # use for personal command menu for users 27 | # scope=telebot.types.BotCommandScopeAllPrivateChats() # use for all private chats 28 | ) 29 | 30 | cmd = await bot.get_my_commands(scope=None, language_code=None) 31 | print([c.to_json() for c in cmd]) 32 | 33 | 34 | if __name__ == '__main__': 35 | asyncio.run(main()) 36 | -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n_gettext/locales/en/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # English translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-18 17:54+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: en\n" 14 | "Language-Team: en \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "" 24 | 25 | #: main.py:78 26 | msgid "" 27 | "Hello, {user_fist_name}!\n" 28 | "This is the example of multilanguage bot.\n" 29 | "Available commands:\n" 30 | "\n" 31 | "/lang - change your language\n" 32 | "/plural - pluralization example" 33 | msgstr "" 34 | 35 | #: main.py:102 36 | msgid "Language has been changed" 37 | msgstr "" 38 | 39 | #: main.py:114 40 | #, fuzzy 41 | msgid "You have {number} click" 42 | msgid_plural "You have {number} clicks" 43 | msgstr[0] "" 44 | msgstr[1] "" 45 | 46 | #: main.py:120 47 | msgid "" 48 | "This is clicker.\n" 49 | "\n" 50 | msgstr "" -------------------------------------------------------------------------------- /examples/middleware/class_based/basic_example.py: -------------------------------------------------------------------------------- 1 | from telebot import TeleBot 2 | from telebot.handler_backends import BaseMiddleware 3 | 4 | bot = TeleBot('TOKEN', use_class_middlewares=True) # set use_class_middlewares to True! 5 | # otherwise, class-based middlewares won't execute. 6 | 7 | # You can use this classes for cancelling update or skipping handler: 8 | # from telebot.handler_backends import CancelUpdate, SkipHandler 9 | 10 | class Middleware(BaseMiddleware): 11 | def __init__(self): 12 | self.update_types = ['message'] 13 | def pre_process(self, message, data): 14 | data['foo'] = 'Hello' # just for example 15 | # we edited the data. now, this data is passed to handler. 16 | # return SkipHandler() -> this will skip handler 17 | # return CancelUpdate() -> this will cancel update 18 | def post_process(self, message, data, exception=None): 19 | print(data['foo']) 20 | if exception: # check for exception 21 | print(exception) 22 | 23 | @bot.message_handler(commands=['start']) 24 | def start(message, data: dict): # you don't have to put data parameter in handler if you don't need it. 25 | bot.send_message(message.chat.id, data['foo']) 26 | data['foo'] = 'Processed' # we changed value of data.. this data is now passed to post_process. 27 | 28 | 29 | # Setup middleware 30 | bot.setup_middleware(Middleware()) 31 | 32 | bot.infinity_polling() 33 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/flooding_middleware.py: -------------------------------------------------------------------------------- 1 | # Just a little example of middleware handlers 2 | 3 | from telebot.asyncio_handler_backends import BaseMiddleware, CancelUpdate 4 | from telebot.async_telebot import AsyncTeleBot 5 | bot = AsyncTeleBot('TOKEN') 6 | 7 | 8 | class SimpleMiddleware(BaseMiddleware): 9 | def __init__(self, limit) -> None: 10 | self.last_time = {} 11 | self.limit = limit 12 | self.update_types = ['message'] 13 | # Always specify update types, otherwise middlewares won't work 14 | 15 | 16 | async def pre_process(self, message, data): 17 | if not message.from_user.id in self.last_time: 18 | # User is not in a dict, so lets add and cancel this function 19 | self.last_time[message.from_user.id] = message.date 20 | return 21 | if message.date - self.last_time[message.from_user.id] < self.limit: 22 | # User is flooding 23 | await bot.send_message(message.chat.id, 'You are making request too often') 24 | return CancelUpdate() 25 | self.last_time[message.from_user.id] = message.date 26 | 27 | 28 | async def post_process(self, message, data, exception): 29 | pass 30 | 31 | bot.setup_middleware(SimpleMiddleware(2)) 32 | 33 | @bot.message_handler(commands=['start']) 34 | async def start(message): 35 | await bot.send_message(message.chat.id, 'Hello!') 36 | 37 | import asyncio 38 | asyncio.run(bot.polling()) 39 | -------------------------------------------------------------------------------- /examples/serverless/aws_lambda_function.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of running PyTelegramBotAPI serverless in Amazon AWS Lambdaю 3 | You have to set your lambda's url as telegram webhook manually https://core.telegram.org/bots/api#setwebhook 4 | """ 5 | 6 | import logging 7 | 8 | import telebot 9 | import json 10 | import os 11 | 12 | API_TOKEN = os.environ['TELEGRAM_TOKEN'] 13 | 14 | 15 | logger = telebot.logger 16 | telebot.logger.setLevel(logging.INFO) 17 | 18 | bot = telebot.TeleBot(API_TOKEN, threaded=False) 19 | 20 | 21 | def process_event(event): 22 | # Get telegram webhook json from event 23 | request_body_dict = json.loads(event['body']) 24 | # Parse updates from json 25 | update = telebot.types.Update.de_json(request_body_dict) 26 | # Run handlers and etc for updates 27 | bot.process_new_updates([update]) 28 | 29 | 30 | def lambda_handler(event, context): 31 | # Process event from aws and respond 32 | process_event(event) 33 | return { 34 | 'statusCode': 200 35 | } 36 | 37 | 38 | # Handle '/start' and '/help' 39 | @bot.message_handler(commands=['help', 'start']) 40 | def send_welcome(message): 41 | bot.reply_to(message, 42 | ("Hi there, I am EchoBot.\n" 43 | "I am here to echo your kind words back to you.")) 44 | 45 | 46 | # Handle all other messages 47 | @bot.message_handler(func=lambda message: True, content_types=['text']) 48 | def echo_message(message): 49 | bot.reply_to(message, message.text) 50 | 51 | -------------------------------------------------------------------------------- /examples/custom_filters/general_custom_filters.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | 3 | bot = telebot.TeleBot('TOKEN') 4 | 5 | 6 | # AdvancedCustomFilter is for list, string filter values 7 | class MainFilter(telebot.custom_filters.AdvancedCustomFilter): 8 | key='text' 9 | @staticmethod 10 | def check(message, text): 11 | return message.text in text 12 | 13 | # SimpleCustomFilter is for boolean values, such as is_admin=True 14 | class IsAdmin(telebot.custom_filters.SimpleCustomFilter): 15 | key='is_admin' 16 | @staticmethod 17 | def check(message: telebot.types.Message): 18 | return bot.get_chat_member(message.chat.id,message.from_user.id).status in ['administrator','creator'] 19 | 20 | 21 | @bot.message_handler(is_admin=True, commands=['admin']) # Check if user is admin 22 | def admin_rep(message): 23 | bot.send_message(message.chat.id, "Hi admin") 24 | 25 | @bot.message_handler(is_admin=False, commands=['admin']) # If user is not admin 26 | def not_admin(message): 27 | bot.send_message(message.chat.id, "You are not admin") 28 | 29 | @bot.message_handler(text=['hi']) # Response to hi message 30 | def welcome_hi(message): 31 | bot.send_message(message.chat.id, 'You said hi') 32 | 33 | @bot.message_handler(text=['bye']) # Response to bye message 34 | def bye_user(message): 35 | bot.send_message(message.chat.id, 'You said bye') 36 | 37 | 38 | # Do not forget to register filters 39 | bot.add_custom_filter(MainFilter()) 40 | bot.add_custom_filter(IsAdmin()) 41 | 42 | bot.infinity_polling(skip_pending=True) # Skip old updates 43 | -------------------------------------------------------------------------------- /examples/webhook_examples/run_webhooks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | # Example on built-in function to receive and process webhooks. 6 | 7 | import telebot 8 | 9 | API_TOKEN = 'TOKEN' 10 | 11 | bot = telebot.TeleBot(API_TOKEN) 12 | 13 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 14 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 15 | DOMAIN = '1.2.3.4' # either domain, or ip address of vps 16 | 17 | # Quick'n'dirty SSL certificate generation: 18 | # 19 | # openssl genrsa -out webhook_pkey.pem 2048 20 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 21 | # 22 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 23 | # with the same value in you put in WEBHOOK_HOST 24 | 25 | 26 | # Handle '/start' and '/help' 27 | @bot.message_handler(commands=['help', 'start']) 28 | def send_welcome(message): 29 | bot.reply_to(message, """\ 30 | Hi there, I am EchoBot. 31 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 32 | """) 33 | 34 | 35 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 36 | @bot.message_handler(func=lambda message: True) 37 | def echo_message(message): 38 | bot.reply_to(message, message.text) 39 | 40 | 41 | bot.run_webhooks( 42 | listen=DOMAIN, 43 | certificate=WEBHOOK_SSL_CERT, 44 | certificate_key=WEBHOOK_SSL_PRIV 45 | ) -------------------------------------------------------------------------------- /examples/middleware/class_based/antiflood_middleware.py: -------------------------------------------------------------------------------- 1 | # Just a little example of middleware handlers 2 | 3 | from telebot.handler_backends import BaseMiddleware 4 | from telebot import TeleBot 5 | from telebot.handler_backends import CancelUpdate 6 | bot = TeleBot('TOKEN', 7 | use_class_middlewares=True) # if you don't set it to true, middlewares won't work 8 | 9 | 10 | class SimpleMiddleware(BaseMiddleware): 11 | def __init__(self, limit) -> None: 12 | self.last_time = {} 13 | self.limit = limit 14 | self.update_types = ['message'] 15 | # Always specify update types, otherwise middlewares won't work 16 | 17 | 18 | def pre_process(self, message, data): 19 | if not message.from_user.id in self.last_time: 20 | # User is not in a dict, so lets add and cancel this function 21 | self.last_time[message.from_user.id] = message.date 22 | return 23 | if message.date - self.last_time[message.from_user.id] < self.limit: 24 | # User is flooding 25 | bot.send_message(message.chat.id, 'You are making request too often') 26 | return CancelUpdate() 27 | self.last_time[message.from_user.id] = message.date 28 | 29 | 30 | def post_process(self, message, data, exception): 31 | pass 32 | 33 | bot.setup_middleware(SimpleMiddleware(2)) 34 | 35 | @bot.message_handler(commands=['start']) 36 | def start(message): # you don't have to put data in handler. 37 | bot.send_message(message.chat.id, 'Hello!') 38 | 39 | bot.infinity_polling() 40 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/timer_bot_async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # This is a simple bot with schedule timer 4 | # https://github.com/ibrb/python-aioschedule 5 | # https://schedule.readthedocs.io 6 | 7 | import asyncio 8 | import aioschedule 9 | from telebot.async_telebot import AsyncTeleBot 10 | 11 | API_TOKEN = '' 12 | bot = AsyncTeleBot(API_TOKEN) 13 | 14 | 15 | async def beep(chat_id) -> None: 16 | """Send the beep message.""" 17 | await bot.send_message(chat_id, text='Beep!') 18 | aioschedule.clear(chat_id) # return schedule.CancelJob not working in aioschedule use tag for delete 19 | 20 | 21 | @bot.message_handler(commands=['help', 'start']) 22 | async def send_welcome(message): 23 | await bot.reply_to(message, "Hi! Use /set to set a timer") 24 | 25 | 26 | @bot.message_handler(commands=['set']) 27 | async def set_timer(message): 28 | args = message.text.split() 29 | if len(args) > 1 and args[1].isdigit(): 30 | sec = int(args[1]) 31 | aioschedule.every(sec).seconds.do(beep, message.chat.id).tag(message.chat.id) 32 | else: 33 | await bot.reply_to(message, 'Usage: /set ') 34 | 35 | 36 | @bot.message_handler(commands=['unset']) 37 | def unset_timer(message): 38 | aioschedule.clean(message.chat.id) 39 | 40 | 41 | async def scheduler(): 42 | while True: 43 | await aioschedule.run_pending() 44 | await asyncio.sleep(1) 45 | 46 | 47 | async def main(): 48 | await asyncio.gather(bot.infinity_polling(), scheduler()) 49 | 50 | 51 | if __name__ == '__main__': 52 | asyncio.run(main()) 53 | -------------------------------------------------------------------------------- /examples/multibot/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask import request, abort 3 | from telebot import TeleBot, types, util 4 | from handlers import register_handlers 5 | 6 | import config 7 | 8 | main_bot = TeleBot(config.MAIN_BOT_TOKEN) 9 | app = Flask(__name__) 10 | tokens = {config.MAIN_BOT_TOKEN: True} 11 | 12 | 13 | @app.route(f"/{config.WEBHOOK_PATH}/", methods=['POST']) 14 | def webhook(token: str): 15 | if not tokens.get(token): 16 | return abort(404) 17 | 18 | if request.headers.get('content-type') != 'application/json': 19 | return abort(403) 20 | 21 | json_string = request.get_data().decode('utf-8') 22 | update = types.Update.de_json(json_string) 23 | if token == main_bot.token: 24 | main_bot.process_new_updates([update]) 25 | return '' 26 | 27 | from_update_bot = TeleBot(token) 28 | register_handlers(from_update_bot) 29 | from_update_bot.process_new_updates([update]) 30 | return '' 31 | 32 | 33 | @main_bot.message_handler(commands=['add_bot']) 34 | def add_bot(message: types.Message): 35 | token = util.extract_arguments(message.text) 36 | tokens[token] = True 37 | 38 | new_bot = TeleBot(token) 39 | new_bot.delete_webhook() 40 | new_bot.set_webhook(f"{config.WEBHOOK_HOST}/{config.WEBHOOK_PATH}/{token}") 41 | 42 | new_bot.send_message(message.chat.id, "Webhook was set.") 43 | 44 | 45 | if __name__ == '__main__': 46 | main_bot.delete_webhook() 47 | main_bot.set_webhook(f"{config.WEBHOOK_HOST}/{config.WEBHOOK_PATH}/{config.MAIN_BOT_TOKEN}") 48 | app.run(host=config.WEBAPP_HOST, port=config.WEBAPP_PORT) 49 | -------------------------------------------------------------------------------- /examples/create_invite_link.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from time import sleep, time 3 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton #Only for creating Inline Buttons, not necessary for creating Invite Links 4 | 5 | Token = "api_token" #Your Bot Access Token 6 | Group_ID = -1234567890 #Group ID for which invite link is to be created 7 | 8 | bot = telebot.TeleBot(Token, parse_mode="HTML") 9 | 10 | #/start command message 11 | @bot.message_handler(commands=['start']) 12 | def startmsg(msg): 13 | bot.reply_to(msg, "Hey there, I'm a bot made by pyTelegramBotAPI!") 14 | 15 | #Get notified of incoming members in group 16 | @bot.message_handler(content_types=['new_chat_members']) 17 | def newmember(msg): 18 | #Create an invite link class that contains info about the created invite link using create_chat_invite_link() with parameters 19 | invite = bot.create_chat_invite_link(Group_ID, member_limit=1, expire_date=int(time())+45) #Here, the link will auto-expire in 45 seconds 20 | InviteLink = invite.invite_link #Get the actual invite link from 'invite' class 21 | 22 | mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup 23 | mrkplink.add(InlineKeyboardButton("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Keyboard 24 | 25 | bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group.", reply_markup=mrkplink) 26 | 27 | #This will send a message with the newly-created invite link as markup button. 28 | #The member limit will be 1 and expiring time will be 45 sec. 29 | 30 | 31 | 32 | 33 | bot.infinity_polling() 34 | -------------------------------------------------------------------------------- /docs/source/locales/en/LC_MESSAGES/install.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../install.rst:3 22 | msgid "Installation Guide" 23 | msgstr "" 24 | 25 | #: ../../install.rst:5 26 | msgid "Installation of pyTelegramBotAPI" 27 | msgstr "" 28 | 29 | #: ../../install.rst:5 30 | msgid "ptba, pytba, pyTelegramBotAPI, installation, guide" 31 | msgstr "" 32 | 33 | #: ../../install.rst:11 34 | msgid "Using PIP" 35 | msgstr "" 36 | 37 | #: ../../install.rst:17 38 | msgid "Using pipenv" 39 | msgstr "" 40 | 41 | #: ../../install.rst:23 42 | msgid "By cloning repository" 43 | msgstr "" 44 | 45 | #: ../../install.rst:31 46 | msgid "Directly using pip" 47 | msgstr "" 48 | 49 | #: ../../install.rst:37 50 | msgid "It is generally recommended to use the first option." 51 | msgstr "" 52 | 53 | #: ../../install.rst:39 54 | msgid "" 55 | "While the API is production-ready, it is still under development and it " 56 | "has regular updates, do not forget to update it regularly by calling:" 57 | msgstr "" 58 | 59 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/webhooks/run_webhooks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This is a simple echo bot using the decorator mechanism. 4 | # It echoes any incoming text messages. 5 | # Example on built-in function to receive and process webhooks. 6 | 7 | from telebot.async_telebot import AsyncTeleBot 8 | import asyncio 9 | bot = AsyncTeleBot('TOKEN') 10 | 11 | 12 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 13 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 14 | DOMAIN = '1.2.3.4' # either domain, or ip address of vps 15 | 16 | # Quick'n'dirty SSL certificate generation: 17 | # 18 | # openssl genrsa -out webhook_pkey.pem 2048 19 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 20 | # 21 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 22 | # with the same value in you put in WEBHOOK_HOST 23 | 24 | 25 | # Handle '/start' and '/help' 26 | @bot.message_handler(commands=['help', 'start']) 27 | async def send_welcome(message): 28 | await bot.reply_to(message, """\ 29 | Hi there, I am EchoBot. 30 | I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ 31 | """) 32 | 33 | 34 | # Handle all other messages with content_type 'text' (content_types defaults to ['text']) 35 | @bot.message_handler(func=lambda message: True) 36 | async def echo_message(message): 37 | await bot.reply_to(message, message.text) 38 | 39 | 40 | # it uses fastapi + uvicorn 41 | asyncio.run(bot.run_webhooks( 42 | listen=DOMAIN, 43 | certificate=WEBHOOK_SSL_CERT, 44 | certificate_key=WEBHOOK_SSL_PRIV 45 | )) -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This example shows how to implement i18n (internationalization) l10n (localization) to create 4 | # multi-language bots with middleware handler. 5 | # 6 | # Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use 7 | # better i18n systems (gettext and etc) for handling multilingual translations. 8 | # This is not a working, production-ready sample and it is highly recommended not to use it in production. 9 | # 10 | # In this example let's imagine we want to introduce localization or internationalization into our project and 11 | # we need some global function to activate the language once and to use that language in all other message 12 | # handler functions for not repeatedly activating it. 13 | # The middleware (i18n and l10n) is explained: 14 | 15 | import telebot 16 | from telebot import apihelper 17 | 18 | apihelper.ENABLE_MIDDLEWARE = True 19 | 20 | TRANSLATIONS = { 21 | 'hello': { 22 | 'en': 'hello', 23 | 'ru': 'привет', 24 | 'uz': 'salom' 25 | } 26 | } 27 | 28 | _lang = 'en' 29 | 30 | 31 | def activate(lang): 32 | global _lang 33 | _lang = lang 34 | 35 | 36 | def _(string): 37 | return TRANSLATIONS[string][_lang] 38 | 39 | 40 | bot = telebot.TeleBot('TOKEN') 41 | 42 | 43 | @bot.middleware_handler(update_types=['message']) 44 | def activate_language(bot_instance, message): 45 | activate(message.from_user.language_code) 46 | 47 | 48 | @bot.message_handler(commands=['start']) 49 | def start(message): 50 | bot.send_message(message.chat.id, _('hello')) 51 | 52 | 53 | bot.infinity_polling() 54 | -------------------------------------------------------------------------------- /examples/middleware/README.md: -------------------------------------------------------------------------------- 1 | # Middlewares 2 | 3 | ## Type of middlewares in pyTelegramBotAPI 4 | Currently, synchronous version of pyTelegramBotAPI has two types of middlewares: 5 | 6 | - Class-based middlewares 7 | - Function-based middlewares 8 | 9 | ## Purpose of middlewares 10 | Middlewares are designed to get update before handler's execution. 11 | 12 | ## Class-based middlewares 13 | This type of middleware has more functionality compared to function-based one. 14 | 15 | Class based middleware should be instance of `telebot.handler_backends.BaseMiddleware.` 16 | 17 | Each middleware should have 2 main functions: 18 | 19 | `pre_process` -> is a method of class which receives update, and data. 20 | 21 | Data - is a dictionary, which could be passed right to handler, and `post_process` function. 22 | 23 | `post_process` -> is a function of class which receives update, data, and exception, that happened in handler. If handler was executed correctly - then exception will equal to None. 24 | 25 | ## Function-based middlewares 26 | To use function-based middleware, you should set `apihelper.ENABLE_MIDDLEWARE = True`. 27 | This type of middleware is created by using a decorator for middleware. 28 | With this type middleware, you can retrieve update immediately after update came. You should set update_types as well. 29 | 30 | ## Why class-based middlewares are better? 31 | - You can pass data between post, pre_process functions, and handler. 32 | - If there is an exception in handler, you will get exception parameter with exception class in post_process. 33 | - Has post_process -> method which works after the handler's execution. 34 | 35 | ## Take a look at examples for more. 36 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. pyTelegramBotAPI documentation master file, created by 2 | sphinx-quickstart on Fri Feb 18 20:58:37 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | 7 | Welcome to pyTelegramBotAPI's documentation! 8 | ============================================ 9 | 10 | .. meta:: 11 | :description: Official documentation of pyTelegramBotAPI 12 | :keywords: ptba, pytba, pyTelegramBotAPI, documentation, guide 13 | 14 | 15 | ======= 16 | TeleBot 17 | ======= 18 | TeleBot is synchronous and asynchronous implementation of `Telegram Bot API `_. 19 | 20 | Chats 21 | ----- 22 | English chat: `Private chat `__ 23 | 24 | Russian chat: `@pytelegrambotapi_talks_ru `__ 25 | 26 | News: `@pyTelegramBotAPI `__ 27 | 28 | Pypi: `Pypi `__ 29 | 30 | Source: `Github repository `__ 31 | 32 | Some features: 33 | -------------- 34 | Easy to learn and use. 35 | 36 | Easy to understand. 37 | 38 | Both sync and async. 39 | 40 | Examples on features. 41 | 42 | States 43 | 44 | And more... 45 | 46 | Content 47 | -------- 48 | .. toctree:: 49 | 50 | install 51 | quick_start 52 | types 53 | sync_version/index 54 | async_version/index 55 | calldata 56 | util 57 | formatting 58 | 59 | 60 | 61 | 62 | Indices and tables 63 | ================== 64 | 65 | * :ref:`genindex` 66 | * :ref:`modindex` 67 | * :ref:`search` 68 | 69 | 70 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from setuptools import setup, find_packages 3 | from io import open 4 | import re 5 | 6 | def read(filename): 7 | with open(filename, encoding='utf-8') as file: 8 | return file.read() 9 | 10 | with open('telebot/version.py', 'r', encoding='utf-8') as f: # Credits: LonamiWebs 11 | version = re.search(r"^__version__\s*=\s*'(.*)'.*$", 12 | f.read(), flags=re.MULTILINE).group(1) 13 | 14 | setup(name='pyTelegramBotAPI', 15 | version=version, 16 | description='Python Telegram bot api. ', 17 | long_description=read('README.md'), 18 | long_description_content_type="text/markdown", 19 | author='eternnoir', 20 | author_email='eternnoir@gmail.com', 21 | url='https://github.com/eternnoir/pyTelegramBotAPI', 22 | packages = find_packages(exclude = ['tests', 'examples']), 23 | license='GPL2', 24 | keywords='telegram bot api tools', 25 | install_requires=['requests'], 26 | extras_require={ 27 | 'json': 'ujson', 28 | 'PIL': 'Pillow', 29 | 'redis': 'redis>=3.4.1', 30 | 'aioredis': 'aioredis', 31 | 'aiohttp': 'aiohttp', 32 | 'fastapi': 'fastapi', 33 | 'uvicorn': 'uvicorn', 34 | 'psutil': 'psutil', 35 | 'coloredlogs': 'coloredlogs', 36 | 'watchdog': 'watchdog' 37 | }, 38 | classifiers=[ 39 | 'Development Status :: 5 - Production/Stable', 40 | 'Programming Language :: Python :: 3', 41 | 'Environment :: Console', 42 | 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 43 | ], 44 | 45 | ) 46 | -------------------------------------------------------------------------------- /examples/chat_member_example.py: -------------------------------------------------------------------------------- 1 | import telebot 2 | from telebot import types,util 3 | 4 | bot = telebot.TeleBot("token") 5 | 6 | #chat_member_handler. When status changes, telegram gives update. check status from old_chat_member and new_chat_member. 7 | @bot.chat_member_handler() 8 | def chat_m(message: types.ChatMemberUpdated): 9 | old = message.old_chat_member 10 | new = message.new_chat_member 11 | if new.status == "member": 12 | bot.send_message(message.chat.id,"Hello {name}!".format(name=new.user.first_name)) # Welcome message 13 | 14 | #if bot is added to group, this handler will work 15 | @bot.my_chat_member_handler() 16 | def my_chat_m(message: types.ChatMemberUpdated): 17 | old = message.old_chat_member 18 | new = message.new_chat_member 19 | if new.status == "member": 20 | bot.send_message(message.chat.id,"Somebody added me to group") # Welcome message, if bot was added to group 21 | bot.leave_chat(message.chat.id) 22 | 23 | #content_Type_service is: 24 | #'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', 25 | #'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', 26 | #'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended', 27 | #'video_chat_participants_invited', 'message_auto_delete_timer_changed' 28 | # this handler deletes service messages 29 | 30 | @bot.message_handler(content_types=util.content_type_service) 31 | def delall(message: types.Message): 32 | bot.delete_message(message.chat.id,message.message_id) 33 | bot.infinity_polling(allowed_updates=util.update_types) 34 | -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n_gettext/locales/uz_Latn/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Uzbek (Latin) translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-18 17:54+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: uz_Latn\n" 14 | "Language-Team: uz_Latn \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "clik" 24 | 25 | #: main.py:78 26 | msgid "" 27 | "Hello, {user_fist_name}!\n" 28 | "This is the example of multilanguage bot.\n" 29 | "Available commands:\n" 30 | "\n" 31 | "/lang - change your language\n" 32 | "/plural - pluralization example" 33 | msgstr "" 34 | "Salom, {user_fist_name}!\n" 35 | "Bu multilanguage bot misoli.\n" 36 | "Mavjud buyruqlar:\n" 37 | "\n" 38 | "/lang - tilni ozgartirish\n" 39 | "/plural - pluralizatsiya misoli" 40 | 41 | #: main.py:102 42 | msgid "Language has been changed" 43 | msgstr "Til ozgartirildi" 44 | 45 | #: main.py:114 46 | msgid "You have {number} click" 47 | msgid_plural "You have {number} clicks" 48 | msgstr[0] "Sizda {number}ta clik" 49 | msgstr[1] "Sizda {number}ta clik" 50 | 51 | #: main.py:120 52 | msgid "" 53 | "This is clicker.\n" 54 | "\n" 55 | msgstr "" 56 | "Bu clicker.\n" 57 | "\n" 58 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_filters/general_custom_filters.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | import telebot 3 | bot = AsyncTeleBot('TOKEN') 4 | 5 | 6 | # AdvancedCustomFilter is for list, string filter values 7 | class MainFilter(telebot.asyncio_filters.AdvancedCustomFilter): 8 | key='text' 9 | @staticmethod 10 | async def check(message, text): 11 | return message.text in text 12 | 13 | # SimpleCustomFilter is for boolean values, such as is_admin=True 14 | class IsAdmin(telebot.asyncio_filters.SimpleCustomFilter): 15 | key='is_admin' 16 | @staticmethod 17 | async def check(message: telebot.types.Message): 18 | result = await bot.get_chat_member(message.chat.id,message.from_user.id) 19 | return result.status in ['administrator','creator'] 20 | 21 | 22 | @bot.message_handler(is_admin=True, commands=['admin']) # Check if user is admin 23 | async def admin_rep(message): 24 | await bot.send_message(message.chat.id, "Hi admin") 25 | 26 | @bot.message_handler(is_admin=False, commands=['admin']) # If user is not admin 27 | async def not_admin(message): 28 | await bot.send_message(message.chat.id, "You are not admin") 29 | 30 | @bot.message_handler(text=['hi']) # Response to hi message 31 | async def welcome_hi(message): 32 | await bot.send_message(message.chat.id, 'You said hi') 33 | 34 | @bot.message_handler(text=['bye']) # Response to bye message 35 | async def bye_user(message): 36 | await bot.send_message(message.chat.id, 'You said bye') 37 | 38 | 39 | # Do not forget to register filters 40 | bot.add_custom_filter(MainFilter()) 41 | bot.add_custom_filter(IsAdmin()) 42 | 43 | import asyncio 44 | asyncio.run(bot.polling()) 45 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/i18n.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This example shows how to implement i18n (internationalization) l10n (localization) to create 4 | # multi-language bots with middleware handler. 5 | # 6 | # Also, you could check language code in handler itself too. 7 | # But this example just to show the work of middlewares. 8 | 9 | import telebot 10 | from telebot.async_telebot import AsyncTeleBot 11 | from telebot import asyncio_handler_backends 12 | import logging 13 | 14 | logger = telebot.logger 15 | telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. 16 | 17 | TRANSLATIONS = { 18 | 'hello': { 19 | 'en': 'hello', 20 | 'ru': 'привет', 21 | 'uz': 'salom' 22 | } 23 | } 24 | 25 | 26 | 27 | bot = AsyncTeleBot('TOKEN') 28 | 29 | 30 | class LanguageMiddleware(asyncio_handler_backends.BaseMiddleware): 31 | def __init__(self): 32 | self.update_types = ['message'] # Update types that will be handled by this middleware. 33 | async def pre_process(self, message, data): 34 | data['response'] = TRANSLATIONS['hello'][message.from_user.language_code] 35 | async def post_process(self, message, data, exception): 36 | if exception: # You can get exception occured in handler. 37 | logger.exception(str(exception)) 38 | 39 | bot.setup_middleware(LanguageMiddleware()) # do not forget to setup 40 | 41 | @bot.message_handler(commands=['start']) 42 | async def start(message, data: dict): 43 | # you can get the data in handler too. 44 | # Not necessary to create data parameter in handler function. 45 | await bot.send_message(message.chat.id, data['response']) 46 | 47 | 48 | import asyncio 49 | asyncio.run(bot.polling()) 50 | -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n_gettext/locales/ru/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Russian translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-18 17:54+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: ru\n" 14 | "Language-Team: ru \n" 15 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " 16 | "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=utf-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "Generated-By: Babel 2.9.1\n" 21 | 22 | #: keyboards.py:20 23 | msgid "click" 24 | msgstr "Клик" 25 | 26 | #: main.py:78 27 | msgid "" 28 | "Hello, {user_fist_name}!\n" 29 | "This is the example of multilanguage bot.\n" 30 | "Available commands:\n" 31 | "\n" 32 | "/lang - change your language\n" 33 | "/plural - pluralization example" 34 | msgstr "" 35 | "Привет, {user_fist_name}!\n" 36 | "Это пример мультиязычного бота.\n" 37 | "Доступные команды:\n" 38 | "\n" 39 | "/lang - изменить язык\n" 40 | "/plural - пример плюрализации" 41 | 42 | #: main.py:102 43 | msgid "Language has been changed" 44 | msgstr "Язык был сменён" 45 | 46 | #: main.py:114 47 | msgid "You have {number} click" 48 | msgid_plural "You have {number} clicks" 49 | msgstr[0] "У вас {number} клик" 50 | msgstr[1] "У вас {number} клика" 51 | msgstr[2] "У вас {number} кликов" 52 | 53 | #: main.py:120 54 | msgid "" 55 | "This is clicker.\n" 56 | "\n" 57 | msgstr "" 58 | "Это кликер.\n" 59 | "\n" -------------------------------------------------------------------------------- /examples/asynchronous_telebot/chat_member_example.py: -------------------------------------------------------------------------------- 1 | from telebot import types,util 2 | from telebot.async_telebot import AsyncTeleBot 3 | 4 | bot = AsyncTeleBot('TOKEN') 5 | 6 | #chat_member_handler. When status changes, telegram gives update. check status from old_chat_member and new_chat_member. 7 | @bot.chat_member_handler() 8 | async def chat_m(message: types.ChatMemberUpdated): 9 | old = message.old_chat_member 10 | new = message.new_chat_member 11 | if new.status == "member": 12 | await bot.send_message(message.chat.id,"Hello {name}!".format(name=new.user.first_name)) # Welcome message 13 | 14 | #if bot is added to group, this handler will work 15 | @bot.my_chat_member_handler() 16 | async def my_chat_m(message: types.ChatMemberUpdated): 17 | old = message.old_chat_member 18 | new = message.new_chat_member 19 | if new.status == "member": 20 | await bot.send_message(message.chat.id,"Somebody added me to group") # Welcome message, if bot was added to group 21 | await bot.leave_chat(message.chat.id) 22 | 23 | #content_Type_service is: 24 | #'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', 25 | #'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', 26 | #'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended', 27 | #'video_chat_participants_invited', 'message_auto_delete_timer_changed' 28 | # this handler deletes service messages 29 | 30 | @bot.message_handler(content_types=util.content_type_service) 31 | async def delall(message: types.Message): 32 | await bot.delete_message(message.chat.id,message.message_id) 33 | import asyncio 34 | asyncio.run(bot.polling(allowed_updates=util.update_types)) 35 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/multibot/main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from aiohttp import web 4 | from telebot import types, util 5 | from telebot.async_telebot import AsyncTeleBot 6 | from handlers import register_handlers 7 | 8 | import config 9 | 10 | main_bot = AsyncTeleBot(config.MAIN_BOT_TOKEN) 11 | app = web.Application() 12 | tokens = {config.MAIN_BOT_TOKEN: True} 13 | 14 | 15 | async def webhook(request): 16 | token = request.match_info.get('token') 17 | if not tokens.get(token): 18 | return web.Response(status=404) 19 | 20 | if request.headers.get('content-type') != 'application/json': 21 | return web.Response(status=403) 22 | 23 | json_string = await request.json() 24 | update = types.Update.de_json(json_string) 25 | if token == main_bot.token: 26 | await main_bot.process_new_updates([update]) 27 | return web.Response() 28 | 29 | from_update_bot = AsyncTeleBot(token) 30 | register_handlers(from_update_bot) 31 | await from_update_bot.process_new_updates([update]) 32 | return web.Response() 33 | 34 | 35 | app.router.add_post("/" + config.WEBHOOK_PATH + "/{token}", webhook) 36 | 37 | 38 | @main_bot.message_handler(commands=['add_bot']) 39 | async def add_bot(message: types.Message): 40 | token = util.extract_arguments(message.text) 41 | tokens[token] = True 42 | 43 | new_bot = AsyncTeleBot(token) 44 | await new_bot.delete_webhook() 45 | await new_bot.set_webhook(f"{config.WEBHOOK_HOST}/{config.WEBHOOK_PATH}/{token}") 46 | 47 | await new_bot.send_message(message.chat.id, "Webhook was set.") 48 | 49 | 50 | async def main(): 51 | await main_bot.delete_webhook() 52 | await main_bot.set_webhook(f"{config.WEBHOOK_HOST}/{config.WEBHOOK_PATH}/{config.MAIN_BOT_TOKEN}") 53 | web.run_app(app, host=config.WEBAPP_HOST, port=config.WEBAPP_PORT) 54 | 55 | if __name__ == '__main__': 56 | asyncio.run(main()) 57 | -------------------------------------------------------------------------------- /examples/formatting_example.py: -------------------------------------------------------------------------------- 1 | from telebot import TeleBot 2 | from telebot import formatting 3 | 4 | bot = TeleBot('TOKEN') 5 | 6 | 7 | @bot.message_handler(commands=['start']) 8 | def start_message(message): 9 | bot.send_message( 10 | message.chat.id, 11 | # function which connects all strings 12 | formatting.format_text( 13 | formatting.mbold(message.from_user.first_name), 14 | formatting.mitalic(message.from_user.first_name), 15 | formatting.munderline(message.from_user.first_name), 16 | formatting.mstrikethrough(message.from_user.first_name), 17 | formatting.mcode(message.from_user.first_name), 18 | separator=" " # separator separates all strings 19 | ), 20 | parse_mode='MarkdownV2' 21 | ) 22 | 23 | # just a bold text using markdownv2 24 | bot.send_message( 25 | message.chat.id, 26 | formatting.mbold(message.from_user.first_name), 27 | parse_mode='MarkdownV2' 28 | ) 29 | 30 | # html 31 | bot.send_message( 32 | message.chat.id, 33 | formatting.format_text( 34 | formatting.hbold(message.from_user.first_name), 35 | formatting.hitalic(message.from_user.first_name), 36 | formatting.hunderline(message.from_user.first_name), 37 | formatting.hstrikethrough(message.from_user.first_name), 38 | formatting.hcode(message.from_user.first_name), 39 | # hide_link is only for html 40 | formatting.hide_link('https://telegra.ph/file/c158e3a6e2a26a160b253.jpg'), 41 | separator=" " 42 | ), 43 | parse_mode='HTML' 44 | ) 45 | 46 | # just a bold text in html 47 | bot.send_message( 48 | message.chat.id, 49 | formatting.hbold(message.from_user.first_name), 50 | parse_mode='HTML' 51 | ) 52 | 53 | bot.infinity_polling() -------------------------------------------------------------------------------- /docs/source/locales/ru/LC_MESSAGES/install.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../install.rst:3 22 | msgid "Installation Guide" 23 | msgstr "Гайд по установке" 24 | 25 | #: ../../install.rst:5 26 | msgid "Installation of pyTelegramBotAPI" 27 | msgstr "Установка pyTelegramBotAPI" 28 | 29 | #: ../../install.rst:5 30 | msgid "ptba, pytba, pyTelegramBotAPI, installation, guide" 31 | msgstr "ptba, pytba, pyTelegramBotAPI, установка, гайд" 32 | 33 | #: ../../install.rst:11 34 | msgid "Using PIP" 35 | msgstr "Используя PIP" 36 | 37 | #: ../../install.rst:17 38 | msgid "Using pipenv" 39 | msgstr "Используя pipenv" 40 | 41 | #: ../../install.rst:23 42 | msgid "By cloning repository" 43 | msgstr "Клонируя репозиторий" 44 | 45 | #: ../../install.rst:31 46 | msgid "Directly using pip" 47 | msgstr "Напрямую используя pip" 48 | 49 | #: ../../install.rst:37 50 | msgid "It is generally recommended to use the first option." 51 | msgstr "Рекомендуется использовать первый вариант." 52 | 53 | #: ../../install.rst:39 54 | msgid "" 55 | "While the API is production-ready, it is still under development and it " 56 | "has regular updates, do not forget to update it regularly by calling:" 57 | msgstr "Новые версии библиотеки имеют больше фич, улучшений и баг фиксов. Не забывайте" 58 | " обновляться вызывая:" 59 | 60 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/formatting_example.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot import formatting 3 | 4 | bot = AsyncTeleBot('token') 5 | 6 | 7 | @bot.message_handler(commands=['start']) 8 | async def start_message(message): 9 | await bot.send_message( 10 | message.chat.id, 11 | # function which connects all strings 12 | formatting.format_text( 13 | formatting.mbold(message.from_user.first_name), 14 | formatting.mitalic(message.from_user.first_name), 15 | formatting.munderline(message.from_user.first_name), 16 | formatting.mstrikethrough(message.from_user.first_name), 17 | formatting.mcode(message.from_user.first_name), 18 | separator=" " # separator separates all strings 19 | ), 20 | parse_mode='MarkdownV2' 21 | ) 22 | 23 | # just a bold text using markdownv2 24 | await bot.send_message( 25 | message.chat.id, 26 | formatting.mbold(message.from_user.first_name), 27 | parse_mode='MarkdownV2' 28 | ) 29 | 30 | # html 31 | await bot.send_message( 32 | message.chat.id, 33 | formatting.format_text( 34 | formatting.hbold(message.from_user.first_name), 35 | formatting.hitalic(message.from_user.first_name), 36 | formatting.hunderline(message.from_user.first_name), 37 | formatting.hstrikethrough(message.from_user.first_name), 38 | formatting.hcode(message.from_user.first_name), 39 | # hide_link is only for html 40 | formatting.hide_link('https://telegra.ph/file/c158e3a6e2a26a160b253.jpg'), 41 | separator=" " 42 | ), 43 | parse_mode='HTML' 44 | ) 45 | 46 | # just a bold text in html 47 | await bot.send_message( 48 | message.chat.id, 49 | formatting.hbold(message.from_user.first_name), 50 | parse_mode='HTML' 51 | ) 52 | 53 | import asyncio 54 | asyncio.run(bot.polling()) -------------------------------------------------------------------------------- /telebot/storage/base_storage.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | class StateStorageBase: 4 | def __init__(self) -> None: 5 | pass 6 | 7 | def set_data(self, chat_id, user_id, key, value): 8 | """ 9 | Set data for a user in a particular chat. 10 | """ 11 | raise NotImplementedError 12 | 13 | def get_data(self, chat_id, user_id): 14 | """ 15 | Get data for a user in a particular chat. 16 | """ 17 | raise NotImplementedError 18 | 19 | def set_state(self, chat_id, user_id, state): 20 | """ 21 | Set state for a particular user. 22 | 23 | ! Note that you should create a 24 | record if it does not exist, and 25 | if a record with state already exists, 26 | you need to update a record. 27 | """ 28 | raise NotImplementedError 29 | 30 | def delete_state(self, chat_id, user_id): 31 | """ 32 | Delete state for a particular user. 33 | """ 34 | raise NotImplementedError 35 | 36 | def reset_data(self, chat_id, user_id): 37 | """ 38 | Reset data for a particular user in a chat. 39 | """ 40 | raise NotImplementedError 41 | 42 | def get_state(self, chat_id, user_id): 43 | raise NotImplementedError 44 | 45 | def get_interactive_data(self, chat_id, user_id): 46 | raise NotImplementedError 47 | 48 | def save(self, chat_id, user_id, data): 49 | raise NotImplementedError 50 | 51 | 52 | 53 | class StateContext: 54 | """ 55 | Class for data. 56 | """ 57 | def __init__(self , obj, chat_id, user_id) -> None: 58 | self.obj = obj 59 | self.data = copy.deepcopy(obj.get_data(chat_id, user_id)) 60 | self.chat_id = chat_id 61 | self.user_id = user_id 62 | 63 | 64 | def __enter__(self): 65 | return self.data 66 | 67 | def __exit__(self, exc_type, exc_val, exc_tb): 68 | return self.obj.save(self.chat_id, self.user_id, self.data) -------------------------------------------------------------------------------- /telebot/asyncio_storage/base_storage.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | 4 | class StateStorageBase: 5 | def __init__(self) -> None: 6 | pass 7 | 8 | async def set_data(self, chat_id, user_id, key, value): 9 | """ 10 | Set data for a user in a particular chat. 11 | """ 12 | raise NotImplementedError 13 | 14 | async def get_data(self, chat_id, user_id): 15 | """ 16 | Get data for a user in a particular chat. 17 | """ 18 | raise NotImplementedError 19 | 20 | async def set_state(self, chat_id, user_id, state): 21 | """ 22 | Set state for a particular user. 23 | 24 | ! Note that you should create a 25 | record if it does not exist, and 26 | if a record with state already exists, 27 | you need to update a record. 28 | """ 29 | raise NotImplementedError 30 | 31 | async def delete_state(self, chat_id, user_id): 32 | """ 33 | Delete state for a particular user. 34 | """ 35 | raise NotImplementedError 36 | 37 | async def reset_data(self, chat_id, user_id): 38 | """ 39 | Reset data for a particular user in a chat. 40 | """ 41 | raise NotImplementedError 42 | 43 | async def get_state(self, chat_id, user_id): 44 | raise NotImplementedError 45 | 46 | async def save(self, chat_id, user_id, data): 47 | raise NotImplementedError 48 | 49 | 50 | class StateContext: 51 | """ 52 | Class for data. 53 | """ 54 | 55 | def __init__(self, obj, chat_id, user_id): 56 | self.obj = obj 57 | self.data = None 58 | self.chat_id = chat_id 59 | self.user_id = user_id 60 | 61 | 62 | 63 | async def __aenter__(self): 64 | self.data = copy.deepcopy(await self.obj.get_data(self.chat_id, self.user_id)) 65 | return self.data 66 | 67 | async def __aexit__(self, exc_type, exc_val, exc_tb): 68 | return await self.obj.save(self.chat_id, self.user_id, self.data) -------------------------------------------------------------------------------- /examples/middleware/class_based/i18n_middleware/locales/en/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # English translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: en\n" 14 | "Language-Team: en \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "" 24 | 25 | #: keyboards.py:29 26 | msgid "My user id" 27 | msgstr "" 28 | 29 | #: keyboards.py:30 30 | msgid "My user name" 31 | msgstr "" 32 | 33 | #: keyboards.py:31 34 | msgid "My first name" 35 | msgstr "" 36 | 37 | #: main.py:97 38 | msgid "" 39 | "Hello, {user_fist_name}!\n" 40 | "This is the example of multilanguage bot.\n" 41 | "Available commands:\n" 42 | "\n" 43 | "/lang - change your language\n" 44 | "/plural - pluralization example\n" 45 | "/menu - text menu example" 46 | msgstr "" 47 | 48 | #: main.py:121 49 | msgid "Language has been changed" 50 | msgstr "" 51 | 52 | #: main.py:130 main.py:150 53 | #, fuzzy 54 | msgid "You have {number} click" 55 | msgid_plural "You have {number} clicks" 56 | msgstr[0] "" 57 | msgstr[1] "" 58 | 59 | #: main.py:135 main.py:155 60 | msgid "" 61 | "This is clicker.\n" 62 | "\n" 63 | msgstr "" 64 | 65 | #: main.py:163 66 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 67 | msgstr "" 68 | 69 | #: main.py:203 70 | msgid "Seems you confused language" 71 | msgstr "" 72 | 73 | #~ msgid "" 74 | #~ "Hello, {user_fist_name}!\n" 75 | #~ "This is the example of multilanguage bot.\n" 76 | #~ "Available commands:\n" 77 | #~ "\n" 78 | #~ "/lang - change your language\n" 79 | #~ "/plural - pluralization example" 80 | #~ msgstr "" 81 | 82 | -------------------------------------------------------------------------------- /examples/serverless/azure_functions: -------------------------------------------------------------------------------- 1 | # Using Azure Functions for serverless bots. 2 | # (Thanks to twitter.com/masyan for the idea) 3 | 4 | # By default the Azure Functions url is https://.../api/HttpTrigger for HttpTrigger type. 5 | # In this example we will use clear webhook url without /api/ -> https://.../HttpTrigger. 6 | # Also we set "authLevel": "anonymous". 7 | 8 | # For HttpTrigger type set "route" and "authLevel" in functions.json 9 | # { 10 | # "bindings": [ 11 | # ... 12 | # "authLevel": "anonymous" 13 | # "route": "HttpTrigger" 14 | # ] 15 | # } 16 | 17 | # To avoid using /api/ in url set "routePrefix":"" in host.json 18 | # { 19 | # ... 20 | # "extensions": { 21 | # "http": { 22 | # "routePrefix": "" 23 | # } 24 | # } 25 | # } 26 | 27 | import logging 28 | 29 | import azure.functions as func 30 | import telebot 31 | from telebot import apihelper, types 32 | 33 | logger = telebot.logger 34 | telebot.logger.setLevel(logging.DEBUG) 35 | 36 | # Set bot token 37 | TOKEN = '' 38 | 39 | # Uncomment this for using proxy for request 40 | # PROXY = '' 41 | # apihelper.proxy = {'https': PROXY} 42 | 43 | # Set WEBHOOK as your Azure Functions url (https://...azurewebsites.net/HttpTrigger) 44 | WEBHOOK = '' 45 | 46 | bot = telebot.TeleBot(TOKEN) 47 | 48 | @bot.message_handler(commands=['start']) 49 | def start(message): 50 | bot.reply_to(message, 'Hello, ' + message.from_user.first_name) 51 | 52 | @bot.message_handler(func=lambda message: True, content_types=['text']) 53 | def echo_message(message): 54 | bot.reply_to(message, message.text) 55 | 56 | # To avoid "error 429 too many request" set webhook only once. Or use time.sleep(1). 57 | def main(req: func.HttpRequest) -> func.HttpResponse: 58 | bot.set_webhook(url=WEBHOOK) 59 | request_body_dict = req.get_json() 60 | update = telebot.types.Update.de_json(request_body_dict) 61 | bot.process_new_messages([update.message]) 62 | return func.HttpResponse(body='', status_code=200) 63 | 64 | # Sometimes "requests" version is important. 65 | # azure-functions==1.0.4 66 | # PySocks==1.7.1 67 | # pyTelegramBotAPI==3.6.6 68 | # requests==2.10.0 69 | 70 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/i18n_middleware_example/locales/en/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # English translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: en\n" 14 | "Language-Team: en \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "" 24 | 25 | #: keyboards.py:29 26 | msgid "My user id" 27 | msgstr "" 28 | 29 | #: keyboards.py:30 30 | msgid "My user name" 31 | msgstr "" 32 | 33 | #: keyboards.py:31 34 | msgid "My first name" 35 | msgstr "" 36 | 37 | #: main.py:97 38 | msgid "" 39 | "Hello, {user_fist_name}!\n" 40 | "This is the example of multilanguage bot.\n" 41 | "Available commands:\n" 42 | "\n" 43 | "/lang - change your language\n" 44 | "/plural - pluralization example\n" 45 | "/menu - text menu example" 46 | msgstr "" 47 | 48 | #: main.py:121 49 | msgid "Language has been changed" 50 | msgstr "" 51 | 52 | #: main.py:130 main.py:150 53 | #, fuzzy 54 | msgid "You have {number} click" 55 | msgid_plural "You have {number} clicks" 56 | msgstr[0] "" 57 | msgstr[1] "" 58 | 59 | #: main.py:135 main.py:155 60 | msgid "" 61 | "This is clicker.\n" 62 | "\n" 63 | msgstr "" 64 | 65 | #: main.py:163 66 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 67 | msgstr "" 68 | 69 | #: main.py:203 70 | msgid "Seems you confused language" 71 | msgstr "" 72 | 73 | #~ msgid "" 74 | #~ "Hello, {user_fist_name}!\n" 75 | #~ "This is the example of multilanguage bot.\n" 76 | #~ "Available commands:\n" 77 | #~ "\n" 78 | #~ "/lang - change your language\n" 79 | #~ "/plural - pluralization example" 80 | #~ msgstr "" 81 | 82 | -------------------------------------------------------------------------------- /examples/middleware/function_based/session.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This example shows how to implement session creation and retrieval based on user id with middleware handler. 4 | # 5 | # Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use 6 | # in-memory or on-disk storage implementations (redis, mysql, postgres and etc) for storing and retrieving structures. 7 | # This is not a working, production-ready sample and it is highly recommended not to use it in production. 8 | # 9 | # In this example let's imagine we want to create a session for each user who communicates with the bot to store 10 | # different kind of temporary data while session is active. As an example we want to track the state of the user 11 | # with the help of this session. So, we need a way to store this session data somewhere globally to enable other 12 | # message handler functions to be able to use it. 13 | # The middleware session is explained: 14 | 15 | import telebot 16 | from telebot import apihelper 17 | 18 | apihelper.ENABLE_MIDDLEWARE = True 19 | 20 | INFO_STATE = 'ON_INFO_MENU' 21 | MAIN_STATE = 'ON_MAIN_MENU' 22 | 23 | SESSIONS = { 24 | -10000: { 25 | 'state': INFO_STATE 26 | }, 27 | -11111: { 28 | 'state': MAIN_STATE 29 | } 30 | } 31 | 32 | 33 | def get_or_create_session(user_id): 34 | try: 35 | return SESSIONS[user_id] 36 | except KeyError: 37 | SESSIONS[user_id] = {'state': MAIN_STATE} 38 | return SESSIONS[user_id] 39 | 40 | 41 | bot = telebot.TeleBot('TOKEN') 42 | 43 | 44 | @bot.middleware_handler(update_types=['message']) 45 | def set_session(bot_instance, message): 46 | bot_instance.session = get_or_create_session(message.from_user.id) 47 | 48 | 49 | @bot.message_handler(commands=['start']) 50 | def start(message): 51 | bot.session['state'] = MAIN_STATE 52 | bot.send_message(message.chat.id, bot.session['state']) 53 | 54 | 55 | @bot.message_handler(commands=['info']) 56 | def start(message): 57 | bot.session['state'] = INFO_STATE 58 | bot.send_message(message.chat.id, bot.session['state']) 59 | 60 | 61 | bot.infinity_polling() 62 | -------------------------------------------------------------------------------- /examples/middleware/class_based/i18n_middleware/locales/uz_Latn/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Uzbek (Latin) translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: uz_Latn\n" 14 | "Language-Team: uz_Latn \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "clik" 24 | 25 | #: keyboards.py:29 26 | msgid "My user id" 27 | msgstr "Mani user id" 28 | 29 | #: keyboards.py:30 30 | msgid "My user name" 31 | msgstr "Mani user name" 32 | 33 | #: keyboards.py:31 34 | msgid "My first name" 35 | msgstr "Mani first name" 36 | 37 | #: main.py:97 38 | msgid "" 39 | "Hello, {user_fist_name}!\n" 40 | "This is the example of multilanguage bot.\n" 41 | "Available commands:\n" 42 | "\n" 43 | "/lang - change your language\n" 44 | "/plural - pluralization example\n" 45 | "/menu - text menu example" 46 | msgstr "" 47 | "Salom, {user_fist_name}!\n" 48 | "Bu multilanguage bot misoli.\n" 49 | "Mavjud buyruqlar:\n" 50 | "\n" 51 | "/lang - tilni ozgartirish\n" 52 | "/plural - pluralizatsiya misoli\n" 53 | "/menu - text menu misoli" 54 | 55 | #: main.py:121 56 | msgid "Language has been changed" 57 | msgstr "Til ozgartirildi" 58 | 59 | #: main.py:130 main.py:150 60 | msgid "You have {number} click" 61 | msgid_plural "You have {number} clicks" 62 | msgstr[0] "Sizda {number}ta clik" 63 | msgstr[1] "Sizda {number}ta clik" 64 | 65 | #: main.py:135 main.py:155 66 | msgid "" 67 | "This is clicker.\n" 68 | "\n" 69 | msgstr "" 70 | "Bu clicker.\n" 71 | "\n" 72 | 73 | #: main.py:163 74 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 75 | msgstr "Bu multilanguage bot da replykeyboardmarkup menyu misoli." 76 | 77 | #: main.py:203 78 | msgid "Seems you confused language" 79 | msgstr "Tilni adashtirdiz" 80 | 81 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/i18n_middleware_example/locales/uz_Latn/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Uzbek (Latin) translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: uz_Latn\n" 14 | "Language-Team: uz_Latn \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: keyboards.py:20 22 | msgid "click" 23 | msgstr "clik" 24 | 25 | #: keyboards.py:29 26 | msgid "My user id" 27 | msgstr "Mani user id" 28 | 29 | #: keyboards.py:30 30 | msgid "My user name" 31 | msgstr "Mani user name" 32 | 33 | #: keyboards.py:31 34 | msgid "My first name" 35 | msgstr "Mani first name" 36 | 37 | #: main.py:97 38 | msgid "" 39 | "Hello, {user_fist_name}!\n" 40 | "This is the example of multilanguage bot.\n" 41 | "Available commands:\n" 42 | "\n" 43 | "/lang - change your language\n" 44 | "/plural - pluralization example\n" 45 | "/menu - text menu example" 46 | msgstr "" 47 | "Salom, {user_fist_name}!\n" 48 | "Bu multilanguage bot misoli.\n" 49 | "Mavjud buyruqlar:\n" 50 | "\n" 51 | "/lang - tilni ozgartirish\n" 52 | "/plural - pluralizatsiya misoli\n" 53 | "/menu - text menu misoli" 54 | 55 | #: main.py:121 56 | msgid "Language has been changed" 57 | msgstr "Til ozgartirildi" 58 | 59 | #: main.py:130 main.py:150 60 | msgid "You have {number} click" 61 | msgid_plural "You have {number} clicks" 62 | msgstr[0] "Sizda {number}ta clik" 63 | msgstr[1] "Sizda {number}ta clik" 64 | 65 | #: main.py:135 main.py:155 66 | msgid "" 67 | "This is clicker.\n" 68 | "\n" 69 | msgstr "" 70 | "Bu clicker.\n" 71 | "\n" 72 | 73 | #: main.py:163 74 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 75 | msgstr "Bu multilanguage bot da replykeyboardmarkup menyu misoli." 76 | 77 | #: main.py:203 78 | msgid "Seems you confused language" 79 | msgstr "Tilni adashtirdiz" 80 | 81 | -------------------------------------------------------------------------------- /telebot/service_utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | from io import BytesIO 4 | 5 | try: 6 | # noinspection PyPackageRequirements 7 | from PIL import Image 8 | pil_imported = True 9 | except ImportError: 10 | pil_imported = False 11 | 12 | 13 | def is_string(var) -> bool: 14 | """ 15 | Returns True if the given object is a string. 16 | """ 17 | return isinstance(var, str) 18 | 19 | 20 | def is_dict(var) -> bool: 21 | """ 22 | Returns True if the given object is a dictionary. 23 | 24 | :param var: object to be checked 25 | :type var: :obj:`object` 26 | 27 | :return: True if the given object is a dictionary. 28 | :rtype: :obj:`bool` 29 | """ 30 | return isinstance(var, dict) 31 | 32 | 33 | def is_bytes(var) -> bool: 34 | """ 35 | Returns True if the given object is a bytes object. 36 | 37 | :param var: object to be checked 38 | :type var: :obj:`object` 39 | 40 | :return: True if the given object is a bytes object. 41 | :rtype: :obj:`bool` 42 | """ 43 | return isinstance(var, bytes) 44 | 45 | 46 | def is_pil_image(var) -> bool: 47 | """ 48 | Returns True if the given object is a PIL.Image.Image object. 49 | 50 | :param var: object to be checked 51 | :type var: :obj:`object` 52 | 53 | :return: True if the given object is a PIL.Image.Image object. 54 | :rtype: :obj:`bool` 55 | """ 56 | return pil_imported and isinstance(var, Image.Image) 57 | 58 | 59 | def pil_image_to_file(image, extension='JPEG', quality='web_low'): 60 | if pil_imported: 61 | photoBuffer = BytesIO() 62 | image.convert('RGB').save(photoBuffer, extension, quality=quality) 63 | photoBuffer.seek(0) 64 | 65 | return photoBuffer 66 | else: 67 | raise RuntimeError('PIL module is not imported') 68 | 69 | 70 | def chunks(lst, n): 71 | """Yield successive n-sized chunks from lst.""" 72 | # https://stackoverflow.com/a/312464/9935473 73 | for i in range(0, len(lst), n): 74 | yield lst[i:i + n] 75 | 76 | 77 | def generate_random_token() -> str: 78 | """ 79 | Generates a random token consisting of letters and digits, 16 characters long. 80 | 81 | :return: a random token 82 | :rtype: :obj:`str` 83 | """ 84 | return ''.join(random.sample(string.ascii_letters, 16)) 85 | -------------------------------------------------------------------------------- /examples/callback_data_examples/advanced_calendar_example/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This Example will show you an advanced usage of CallbackData. 4 | In this example calendar was implemented 5 | """ 6 | 7 | from datetime import date 8 | 9 | from examples.callback_data_examples.advanced_calendar_example.keyboards import generate_calendar_days, \ 10 | generate_calendar_months, EMTPY_FIELD 11 | from filters import calendar_factory, calendar_zoom, bind_filters 12 | from telebot import types, TeleBot 13 | 14 | API_TOKEN = '' 15 | bot = TeleBot(API_TOKEN) 16 | 17 | 18 | @bot.message_handler(commands='start') 19 | def start_command_handler(message: types.Message): 20 | bot.send_message(message.chat.id, 21 | f"Hello {message.from_user.first_name}. This bot is an example of calendar keyboard." 22 | "\nPress /calendar to see it.") 23 | 24 | 25 | @bot.message_handler(commands='calendar') 26 | def calendar_command_handler(message: types.Message): 27 | now = date.today() 28 | bot.send_message(message.chat.id, 'Calendar', reply_markup=generate_calendar_days(year=now.year, month=now.month)) 29 | 30 | 31 | @bot.callback_query_handler(func=None, calendar_config=calendar_factory.filter()) 32 | def calendar_action_handler(call: types.CallbackQuery): 33 | callback_data: dict = calendar_factory.parse(callback_data=call.data) 34 | year, month = int(callback_data['year']), int(callback_data['month']) 35 | 36 | bot.edit_message_reply_markup(call.message.chat.id, call.message.id, 37 | reply_markup=generate_calendar_days(year=year, month=month)) 38 | 39 | 40 | @bot.callback_query_handler(func=None, calendar_zoom_config=calendar_zoom.filter()) 41 | def calendar_zoom_out_handler(call: types.CallbackQuery): 42 | callback_data: dict = calendar_zoom.parse(callback_data=call.data) 43 | year = int(callback_data.get('year')) 44 | 45 | bot.edit_message_reply_markup(call.message.chat.id, call.message.id, 46 | reply_markup=generate_calendar_months(year=year)) 47 | 48 | 49 | @bot.callback_query_handler(func=lambda call: call.data == EMTPY_FIELD) 50 | def callback_empty_field_handler(call: types.CallbackQuery): 51 | bot.answer_callback_query(call.id) 52 | 53 | 54 | if __name__ == '__main__': 55 | bind_filters(bot) 56 | bot.infinity_polling() 57 | -------------------------------------------------------------------------------- /examples/middleware/class_based/i18n_middleware/locales/ru/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Russian translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: ru\n" 14 | "Language-Team: ru \n" 15 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " 16 | "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=utf-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "Generated-By: Babel 2.9.1\n" 21 | 22 | #: keyboards.py:20 23 | msgid "click" 24 | msgstr "Клик" 25 | 26 | #: keyboards.py:29 27 | msgid "My user id" 28 | msgstr "Мой user id" 29 | 30 | #: keyboards.py:30 31 | msgid "My user name" 32 | msgstr "Мой user name" 33 | 34 | #: keyboards.py:31 35 | msgid "My first name" 36 | msgstr "Мой first name" 37 | 38 | #: main.py:97 39 | msgid "" 40 | "Hello, {user_fist_name}!\n" 41 | "This is the example of multilanguage bot.\n" 42 | "Available commands:\n" 43 | "\n" 44 | "/lang - change your language\n" 45 | "/plural - pluralization example\n" 46 | "/menu - text menu example" 47 | msgstr "" 48 | "Привет, {user_fist_name}!\n" 49 | "Это пример мультиязычного бота.\n" 50 | "Доступные команды:\n" 51 | "\n" 52 | "/lang - изменить язык\n" 53 | "/plural - пример плюрализации\n" 54 | "/menu - Пример текстового меню" 55 | 56 | #: main.py:121 57 | msgid "Language has been changed" 58 | msgstr "Язык был сменён" 59 | 60 | #: main.py:130 main.py:150 61 | msgid "You have {number} click" 62 | msgid_plural "You have {number} clicks" 63 | msgstr[0] "У вас {number} клик" 64 | msgstr[1] "У вас {number} клика" 65 | msgstr[2] "У вас {number} кликов" 66 | 67 | #: main.py:135 main.py:155 68 | msgid "" 69 | "This is clicker.\n" 70 | "\n" 71 | msgstr "" 72 | "Это кликер.\n" 73 | "\n" 74 | 75 | #: main.py:163 76 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 77 | msgstr "Это пример ReplyKeyboardMarkup меню в мультиязычном боте." 78 | 79 | #: main.py:203 80 | msgid "Seems you confused language" 81 | msgstr "Кажется, вы перепутали язык" 82 | 83 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/middleware/i18n_middleware_example/locales/ru/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Russian translations for PROJECT. 2 | # Copyright (C) 2022 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2022-02-19 18:37+0500\n" 11 | "PO-Revision-Date: 2022-02-18 16:22+0500\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: ru\n" 14 | "Language-Team: ru \n" 15 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " 16 | "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=utf-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "Generated-By: Babel 2.9.1\n" 21 | 22 | #: keyboards.py:20 23 | msgid "click" 24 | msgstr "Клик" 25 | 26 | #: keyboards.py:29 27 | msgid "My user id" 28 | msgstr "Мой user id" 29 | 30 | #: keyboards.py:30 31 | msgid "My user name" 32 | msgstr "Мой user name" 33 | 34 | #: keyboards.py:31 35 | msgid "My first name" 36 | msgstr "Мой first name" 37 | 38 | #: main.py:97 39 | msgid "" 40 | "Hello, {user_fist_name}!\n" 41 | "This is the example of multilanguage bot.\n" 42 | "Available commands:\n" 43 | "\n" 44 | "/lang - change your language\n" 45 | "/plural - pluralization example\n" 46 | "/menu - text menu example" 47 | msgstr "" 48 | "Привет, {user_fist_name}!\n" 49 | "Это пример мультиязычного бота.\n" 50 | "Доступные команды:\n" 51 | "\n" 52 | "/lang - изменить язык\n" 53 | "/plural - пример плюрализации\n" 54 | "/menu - Пример текстового меню" 55 | 56 | #: main.py:121 57 | msgid "Language has been changed" 58 | msgstr "Язык был сменён" 59 | 60 | #: main.py:130 main.py:150 61 | msgid "You have {number} click" 62 | msgid_plural "You have {number} clicks" 63 | msgstr[0] "У вас {number} клик" 64 | msgstr[1] "У вас {number} клика" 65 | msgstr[2] "У вас {number} кликов" 66 | 67 | #: main.py:135 main.py:155 68 | msgid "" 69 | "This is clicker.\n" 70 | "\n" 71 | msgstr "" 72 | "Это кликер.\n" 73 | "\n" 74 | 75 | #: main.py:163 76 | msgid "This is ReplyKeyboardMarkup menu example in multilanguage bot." 77 | msgstr "Это пример ReplyKeyboardMarkup меню в мультиязычном боте." 78 | 79 | #: main.py:203 80 | msgid "Seems you confused language" 81 | msgstr "Кажется, вы перепутали язык" 82 | 83 | -------------------------------------------------------------------------------- /examples/webhook_examples/README.md: -------------------------------------------------------------------------------- 1 | # Webhook examples using pyTelegramBotAPI 2 | 3 | There are 5 examples in this directory using different libraries: 4 | 5 | * **Python (CPython):** *webhook_cpython_echo_bot.py* 6 | * **Pros:** 7 | * Official python libraries, it works out of the box (doesn't require to 8 | install anything). 9 | * Works with Python 2 and Python 3 (need to be converted with 2to3). 10 | * **Cons:** 11 | * Ugly code. 12 | * Many things to handle yourself, this can lead to errors. 13 | * Not powerful, do the trick but the performance is low. 14 | 15 | * **CherryPy (3.8.0):** *webhook_cherrypy_echo_bot.py* 16 | * **Pros:** 17 | * It's a web application framework, cleaner code, uses objects for defining 18 | the web application. 19 | * Very good performance. 20 | * The project seems to be active, latest version is recent. 21 | * Works with Python 2 and Python 3. 22 | * **Cons:** 23 | * Some things are not very intuitive, reading the doc is a must. 24 | 25 | * **Flask (0.10.1):** *webhook_flask_echo_bot.py* 26 | * **Pros:** 27 | * It's a web application framework, cleaner code, uses decorator which can 28 | be nice. 29 | * Good performance. 30 | * It's intuitive if you know how web application works. 31 | * **Cons:** 32 | * The project seems not to be very active, latest version dates 2013. 33 | * They don't recommend to use it with Python 3, but may work. 34 | * May be a oversized for just handling webhook petitions. 35 | 36 | * **aiohttp (1.2.0):** *webhook_aiohttp_echo_bot.py* 37 | * **Pros:** 38 | * It's a web application framework 39 | * Python 3 compatible 40 | * Asynchronous, excellent performance 41 | * Utilizes new async/await syntax 42 | * **Cons:** 43 | * Requires Python 3.4.2+, don't work with Python 2 44 | 45 | * **Twisted (20.3.0):** *webhook_twisted_echo_bot.py* 46 | * **Pros:** 47 | * Asynchronous event-driven networking engine 48 | * Very high performance 49 | * Built-in support for many internet protocols 50 | * **Cons:** 51 | * Twisted is low-level, which may be good or bad depending on use case 52 | * Considerable learning curve - reading docs is a must. 53 | * **FastAPI(0.70.1):** *webhook_fastapi_echo_bot.py* 54 | * **Pros:** 55 | * Can be written for both sync and async 56 | * Good documentation 57 | * **Cons:** 58 | * Requires python 3.6+ 59 | 60 | 61 | *Latest update of this document: 01-03-2022 62 | -------------------------------------------------------------------------------- /examples/middleware/function_based/i18n_gettext/i18n_class.py: -------------------------------------------------------------------------------- 1 | import gettext 2 | import os 3 | import threading 4 | 5 | 6 | class I18N: 7 | """ 8 | This class provides high-level tool for internationalization 9 | It is based on gettext util. 10 | """ 11 | 12 | context_lang = threading.local() 13 | 14 | def __init__(self, translations_path, domain_name: str): 15 | self.path = translations_path 16 | self.domain = domain_name 17 | self.translations = self.find_translations() 18 | 19 | @property 20 | def available_translations(self): 21 | return list(self.translations) 22 | 23 | def gettext(self, text: str, lang: str = None): 24 | """ 25 | Singular translations 26 | """ 27 | 28 | if lang is None: 29 | lang = self.context_lang.language 30 | 31 | if lang not in self.translations: 32 | return text 33 | 34 | translator = self.translations[lang] 35 | return translator.gettext(text) 36 | 37 | def ngettext(self, singular: str, plural: str, lang: str = None, n=1): 38 | """ 39 | Plural translations 40 | """ 41 | if lang is None: 42 | lang = self.context_lang.language 43 | 44 | if lang not in self.translations: 45 | if n == 1: 46 | return singular 47 | return plural 48 | 49 | translator = self.translations[lang] 50 | return translator.ngettext(singular, plural, n) 51 | 52 | 53 | def find_translations(self): 54 | """ 55 | Looks for translations with passed 'domain' in passed 'path' 56 | """ 57 | if not os.path.exists(self.path): 58 | raise RuntimeError(f"Translations directory by path: {self.path!r} was not found") 59 | 60 | result = {} 61 | 62 | for name in os.listdir(self.path): 63 | translations_path = os.path.join(self.path, name, 'LC_MESSAGES') 64 | 65 | if not os.path.isdir(translations_path): 66 | continue 67 | 68 | po_file = os.path.join(translations_path, self.domain + '.po') 69 | mo_file = po_file[:-2] + 'mo' 70 | 71 | if os.path.isfile(po_file) and not os.path.isfile(mo_file): 72 | raise FileNotFoundError(f"Translations for: {name!r} were not compiled!") 73 | 74 | with open(mo_file, 'rb') as file: 75 | result[name] = gettext.GNUTranslations(file) 76 | 77 | return result 78 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/callback_data_examples/advanced_calendar_example/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This Example will show you an advanced usage of CallbackData. 4 | In this example calendar was implemented 5 | """ 6 | import asyncio 7 | from datetime import date 8 | 9 | from filters import calendar_factory, calendar_zoom, bind_filters 10 | from keyboards import generate_calendar_days, generate_calendar_months, EMTPY_FIELD 11 | from telebot import types 12 | from telebot.async_telebot import AsyncTeleBot 13 | 14 | API_TOKEN = '' 15 | bot = AsyncTeleBot(API_TOKEN) 16 | 17 | 18 | @bot.message_handler(commands='start') 19 | async def start_command_handler(message: types.Message): 20 | await bot.send_message(message.chat.id, 21 | f"Hello {message.from_user.first_name}. This bot is an example of calendar keyboard." 22 | "\nPress /calendar to see it.") 23 | 24 | 25 | @bot.message_handler(commands='calendar') 26 | async def calendar_command_handler(message: types.Message): 27 | now = date.today() 28 | await bot.send_message(message.chat.id, 'Calendar', 29 | reply_markup=generate_calendar_days(year=now.year, month=now.month)) 30 | 31 | 32 | @bot.callback_query_handler(func=None, calendar_config=calendar_factory.filter()) 33 | async def calendar_action_handler(call: types.CallbackQuery): 34 | callback_data: dict = calendar_factory.parse(callback_data=call.data) 35 | year, month = int(callback_data['year']), int(callback_data['month']) 36 | 37 | await bot.edit_message_reply_markup(call.message.chat.id, call.message.id, 38 | reply_markup=generate_calendar_days(year=year, month=month)) 39 | 40 | 41 | @bot.callback_query_handler(func=None, calendar_zoom_config=calendar_zoom.filter()) 42 | async def calendar_zoom_out_handler(call: types.CallbackQuery): 43 | callback_data: dict = calendar_zoom.parse(callback_data=call.data) 44 | year = int(callback_data.get('year')) 45 | 46 | await bot.edit_message_reply_markup(call.message.chat.id, call.message.id, 47 | reply_markup=generate_calendar_months(year=year)) 48 | 49 | 50 | @bot.callback_query_handler(func=lambda call: call.data == EMTPY_FIELD) 51 | async def callback_empty_field_handler(call: types.CallbackQuery): 52 | await bot.answer_callback_query(call.id) 53 | 54 | 55 | if __name__ == '__main__': 56 | bind_filters(bot) 57 | asyncio.run(bot.infinity_polling()) 58 | -------------------------------------------------------------------------------- /telebot/storage/memory_storage.py: -------------------------------------------------------------------------------- 1 | from telebot.storage.base_storage import StateStorageBase, StateContext 2 | 3 | 4 | class StateMemoryStorage(StateStorageBase): 5 | def __init__(self) -> None: 6 | super().__init__() 7 | self.data = {} 8 | # 9 | # {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...} 10 | 11 | 12 | def set_state(self, chat_id, user_id, state): 13 | if hasattr(state, 'name'): 14 | state = state.name 15 | if chat_id in self.data: 16 | if user_id in self.data[chat_id]: 17 | self.data[chat_id][user_id]['state'] = state 18 | return True 19 | else: 20 | self.data[chat_id][user_id] = {'state': state, 'data': {}} 21 | return True 22 | self.data[chat_id] = {user_id: {'state': state, 'data': {}}} 23 | return True 24 | 25 | def delete_state(self, chat_id, user_id): 26 | if self.data.get(chat_id): 27 | if self.data[chat_id].get(user_id): 28 | del self.data[chat_id][user_id] 29 | if chat_id == user_id: 30 | del self.data[chat_id] 31 | 32 | return True 33 | 34 | return False 35 | 36 | 37 | def get_state(self, chat_id, user_id): 38 | 39 | if self.data.get(chat_id): 40 | if self.data[chat_id].get(user_id): 41 | return self.data[chat_id][user_id]['state'] 42 | 43 | return None 44 | def get_data(self, chat_id, user_id): 45 | if self.data.get(chat_id): 46 | if self.data[chat_id].get(user_id): 47 | return self.data[chat_id][user_id]['data'] 48 | 49 | return None 50 | 51 | def reset_data(self, chat_id, user_id): 52 | if self.data.get(chat_id): 53 | if self.data[chat_id].get(user_id): 54 | self.data[chat_id][user_id]['data'] = {} 55 | return True 56 | return False 57 | 58 | def set_data(self, chat_id, user_id, key, value): 59 | if self.data.get(chat_id): 60 | if self.data[chat_id].get(user_id): 61 | self.data[chat_id][user_id]['data'][key] = value 62 | return True 63 | raise RuntimeError('chat_id {} and user_id {} does not exist'.format(chat_id, user_id)) 64 | 65 | def get_interactive_data(self, chat_id, user_id): 66 | return StateContext(self, chat_id, user_id) 67 | 68 | def save(self, chat_id, user_id, data): 69 | self.data[chat_id][user_id]['data'] = data -------------------------------------------------------------------------------- /telebot/asyncio_storage/memory_storage.py: -------------------------------------------------------------------------------- 1 | from telebot.asyncio_storage.base_storage import StateStorageBase, StateContext 2 | 3 | class StateMemoryStorage(StateStorageBase): 4 | def __init__(self) -> None: 5 | self.data = {} 6 | # 7 | # {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...} 8 | 9 | 10 | async def set_state(self, chat_id, user_id, state): 11 | if hasattr(state, 'name'): 12 | state = state.name 13 | if chat_id in self.data: 14 | if user_id in self.data[chat_id]: 15 | self.data[chat_id][user_id]['state'] = state 16 | return True 17 | else: 18 | self.data[chat_id][user_id] = {'state': state, 'data': {}} 19 | return True 20 | self.data[chat_id] = {user_id: {'state': state, 'data': {}}} 21 | return True 22 | 23 | async def delete_state(self, chat_id, user_id): 24 | if self.data.get(chat_id): 25 | if self.data[chat_id].get(user_id): 26 | del self.data[chat_id][user_id] 27 | if chat_id == user_id: 28 | del self.data[chat_id] 29 | 30 | return True 31 | 32 | return False 33 | 34 | 35 | async def get_state(self, chat_id, user_id): 36 | if self.data.get(chat_id): 37 | if self.data[chat_id].get(user_id): 38 | return self.data[chat_id][user_id]['state'] 39 | 40 | return None 41 | async def get_data(self, chat_id, user_id): 42 | if self.data.get(chat_id): 43 | if self.data[chat_id].get(user_id): 44 | return self.data[chat_id][user_id]['data'] 45 | 46 | return None 47 | 48 | async def reset_data(self, chat_id, user_id): 49 | if self.data.get(chat_id): 50 | if self.data[chat_id].get(user_id): 51 | self.data[chat_id][user_id]['data'] = {} 52 | return True 53 | return False 54 | 55 | async def set_data(self, chat_id, user_id, key, value): 56 | if self.data.get(chat_id): 57 | if self.data[chat_id].get(user_id): 58 | self.data[chat_id][user_id]['data'][key] = value 59 | return True 60 | raise RuntimeError('chat_id {} and user_id {} does not exist'.format(chat_id, user_id)) 61 | 62 | def get_interactive_data(self, chat_id, user_id): 63 | return StateContext(self, chat_id, user_id) 64 | 65 | async def save(self, chat_id, user_id, data): 66 | self.data[chat_id][user_id]['data'] = data -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'pyTelegramBotAPI Documentation' 21 | copyright = '2022, coder2020official' 22 | author = 'coder2020official' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '4.10.0' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.autosectionlabel', 35 | 'sphinx.ext.autodoc', 36 | "sphinx.ext.autosummary", 37 | "sphinx.ext.napoleon", 38 | "sphinx_copybutton", 39 | 40 | ] 41 | 42 | # Add any paths that contain templates here, relative to this directory. 43 | templates_path = ['_templates'] 44 | 45 | # List of patterns, relative to source directory, that match files and 46 | # directories to ignore when looking for source files. 47 | # This pattern also affects html_static_path and html_extra_path. 48 | exclude_patterns = [] 49 | 50 | 51 | # -- Options for HTML output ------------------------------------------------- 52 | 53 | # The theme to use for HTML and HTML Help pages. See the documentation for 54 | # a list of builtin themes. 55 | # 56 | html_theme = 'furo' 57 | 58 | # Add any paths that contain custom static files (such as style sheets) here, 59 | # relative to this directory. They are copied after the builtin static files, 60 | # so a file named "default.css" will overwrite the builtin "default.css". 61 | html_static_path = ['_static'] 62 | #html_logo = 'logo.png' 63 | html_theme_options = { 64 | "light_css_variables": { 65 | "color-brand-primary": "#7C4DFF", 66 | "color-brand-content": "#7C4DFF", 67 | }, 68 | "light_logo": "logo.png", 69 | "dark_logo": "logo2.png", 70 | } 71 | 72 | locale_dirs = ["locales/"] 73 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_fastapi_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a simple echo bot using decorators and webhook with fastapi 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | import logging 8 | import fastapi 9 | import uvicorn 10 | import telebot 11 | 12 | API_TOKEN = 'TOKEN' 13 | 14 | WEBHOOK_HOST = '' 15 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 16 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 17 | 18 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 19 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 20 | 21 | # Quick'n'dirty SSL certificate generation: 22 | # 23 | # openssl genrsa -out webhook_pkey.pem 2048 24 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 25 | # 26 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 27 | # with the same value in you put in WEBHOOK_HOST 28 | 29 | WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) 30 | WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) 31 | 32 | logger = telebot.logger 33 | telebot.logger.setLevel(logging.INFO) 34 | 35 | bot = telebot.TeleBot(API_TOKEN) 36 | 37 | app = fastapi.FastAPI(docs=None, redoc_url=None) 38 | 39 | 40 | @app.post(f'/{API_TOKEN}/') 41 | def process_webhook(update: dict): 42 | """ 43 | Process webhook calls 44 | """ 45 | if update: 46 | update = telebot.types.Update.de_json(update) 47 | bot.process_new_updates([update]) 48 | else: 49 | return 50 | 51 | 52 | @bot.message_handler(commands=['help', 'start']) 53 | def send_welcome(message): 54 | """ 55 | Handle '/start' and '/help' 56 | """ 57 | bot.reply_to(message, 58 | ("Hi there, I am EchoBot.\n" 59 | "I am here to echo your kind words back to you.")) 60 | 61 | 62 | @bot.message_handler(func=lambda message: True, content_types=['text']) 63 | def echo_message(message): 64 | """ 65 | Handle all other messages 66 | """ 67 | bot.reply_to(message, message.text) 68 | 69 | 70 | # Remove webhook, it fails sometimes the set if there is a previous webhook 71 | bot.remove_webhook() 72 | 73 | # Set webhook 74 | bot.set_webhook( 75 | url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 76 | certificate=open(WEBHOOK_SSL_CERT, 'r') 77 | ) 78 | 79 | 80 | uvicorn.run( 81 | app, 82 | host=WEBHOOK_LISTEN, 83 | port=WEBHOOK_PORT, 84 | ssl_certfile=WEBHOOK_SSL_CERT, 85 | ssl_keyfile=WEBHOOK_SSL_PRIV 86 | ) 87 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_aiohttp_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a simple echo bot using decorators and webhook with aiohttp 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | import logging 8 | import ssl 9 | 10 | from aiohttp import web 11 | 12 | import telebot 13 | 14 | API_TOKEN = '' 15 | 16 | WEBHOOK_HOST = '' 17 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 18 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 19 | 20 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 21 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 22 | 23 | # Quick'n'dirty SSL certificate generation: 24 | # 25 | # openssl genrsa -out webhook_pkey.pem 2048 26 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 27 | # 28 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 29 | # with the same value in you put in WEBHOOK_HOST 30 | 31 | WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) 32 | WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) 33 | 34 | logger = telebot.logger 35 | telebot.logger.setLevel(logging.INFO) 36 | 37 | bot = telebot.TeleBot(API_TOKEN) 38 | 39 | app = web.Application() 40 | 41 | 42 | # Process webhook calls 43 | async def handle(request): 44 | if request.match_info.get('token') == bot.token: 45 | request_body_dict = await request.json() 46 | update = telebot.types.Update.de_json(request_body_dict) 47 | bot.process_new_updates([update]) 48 | return web.Response() 49 | else: 50 | return web.Response(status=403) 51 | 52 | 53 | app.router.add_post('/{token}/', handle) 54 | 55 | 56 | # Handle '/start' and '/help' 57 | @bot.message_handler(commands=['help', 'start']) 58 | def send_welcome(message): 59 | bot.reply_to(message, 60 | ("Hi there, I am EchoBot.\n" 61 | "I am here to echo your kind words back to you.")) 62 | 63 | 64 | # Handle all other messages 65 | @bot.message_handler(func=lambda message: True, content_types=['text']) 66 | def echo_message(message): 67 | bot.reply_to(message, message.text) 68 | 69 | 70 | # Remove webhook, it fails sometimes the set if there is a previous webhook 71 | bot.remove_webhook() 72 | 73 | # Set webhook 74 | bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 75 | certificate=open(WEBHOOK_SSL_CERT, 'r')) 76 | 77 | # Build ssl context 78 | context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 79 | context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV) 80 | 81 | # Start aiohttp server 82 | web.run_app( 83 | app, 84 | host=WEBHOOK_LISTEN, 85 | port=WEBHOOK_PORT, 86 | ssl_context=context, 87 | ) 88 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_flask_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a simple echo bot using decorators and webhook with flask 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | import logging 8 | import time 9 | 10 | import flask 11 | 12 | import telebot 13 | 14 | API_TOKEN = '' 15 | 16 | WEBHOOK_HOST = '' 17 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 18 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 19 | 20 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 21 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 22 | 23 | # Quick'n'dirty SSL certificate generation: 24 | # 25 | # openssl genrsa -out webhook_pkey.pem 2048 26 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 27 | # 28 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 29 | # with the same value in you put in WEBHOOK_HOST 30 | 31 | WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) 32 | WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) 33 | 34 | logger = telebot.logger 35 | telebot.logger.setLevel(logging.INFO) 36 | 37 | bot = telebot.TeleBot(API_TOKEN) 38 | 39 | app = flask.Flask(__name__) 40 | 41 | 42 | # Empty webserver index, return nothing, just http 200 43 | @app.route('/', methods=['GET', 'HEAD']) 44 | def index(): 45 | return '' 46 | 47 | 48 | # Process webhook calls 49 | @app.route(WEBHOOK_URL_PATH, methods=['POST']) 50 | def webhook(): 51 | if flask.request.headers.get('content-type') == 'application/json': 52 | json_string = flask.request.get_data().decode('utf-8') 53 | update = telebot.types.Update.de_json(json_string) 54 | bot.process_new_updates([update]) 55 | return '' 56 | else: 57 | flask.abort(403) 58 | 59 | 60 | # Handle '/start' and '/help' 61 | @bot.message_handler(commands=['help', 'start']) 62 | def send_welcome(message): 63 | bot.reply_to(message, 64 | ("Hi there, I am EchoBot.\n" 65 | "I am here to echo your kind words back to you.")) 66 | 67 | 68 | # Handle all other messages 69 | @bot.message_handler(func=lambda message: True, content_types=['text']) 70 | def echo_message(message): 71 | bot.reply_to(message, message.text) 72 | 73 | 74 | # Remove webhook, it fails sometimes the set if there is a previous webhook 75 | bot.remove_webhook() 76 | 77 | time.sleep(0.1) 78 | 79 | # Set webhook 80 | bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 81 | certificate=open(WEBHOOK_SSL_CERT, 'r')) 82 | 83 | # Start flask server 84 | app.run(host=WEBHOOK_LISTEN, 85 | port=WEBHOOK_PORT, 86 | ssl_context=(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV), 87 | debug=True) 88 | -------------------------------------------------------------------------------- /examples/step_example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This Example will show you how to use register_next_step handler. 4 | """ 5 | 6 | import telebot 7 | from telebot import types 8 | 9 | API_TOKEN = '' 10 | 11 | bot = telebot.TeleBot(API_TOKEN) 12 | 13 | user_dict = {} 14 | 15 | 16 | class User: 17 | def __init__(self, name): 18 | self.name = name 19 | self.age = None 20 | self.sex = None 21 | 22 | 23 | # Handle '/start' and '/help' 24 | @bot.message_handler(commands=['help', 'start']) 25 | def send_welcome(message): 26 | msg = bot.reply_to(message, """\ 27 | Hi there, I am Example bot. 28 | What's your name? 29 | """) 30 | bot.register_next_step_handler(msg, process_name_step) 31 | 32 | 33 | def process_name_step(message): 34 | try: 35 | chat_id = message.chat.id 36 | name = message.text 37 | user = User(name) 38 | user_dict[chat_id] = user 39 | msg = bot.reply_to(message, 'How old are you?') 40 | bot.register_next_step_handler(msg, process_age_step) 41 | except Exception as e: 42 | bot.reply_to(message, 'oooops') 43 | 44 | 45 | def process_age_step(message): 46 | try: 47 | chat_id = message.chat.id 48 | age = message.text 49 | if not age.isdigit(): 50 | msg = bot.reply_to(message, 'Age should be a number. How old are you?') 51 | bot.register_next_step_handler(msg, process_age_step) 52 | return 53 | user = user_dict[chat_id] 54 | user.age = age 55 | markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) 56 | markup.add('Male', 'Female') 57 | msg = bot.reply_to(message, 'What is your gender', reply_markup=markup) 58 | bot.register_next_step_handler(msg, process_sex_step) 59 | except Exception as e: 60 | bot.reply_to(message, 'oooops') 61 | 62 | 63 | def process_sex_step(message): 64 | try: 65 | chat_id = message.chat.id 66 | sex = message.text 67 | user = user_dict[chat_id] 68 | if (sex == u'Male') or (sex == u'Female'): 69 | user.sex = sex 70 | else: 71 | raise Exception("Unknown sex") 72 | bot.send_message(chat_id, 'Nice to meet you ' + user.name + '\n Age:' + str(user.age) + '\n Sex:' + user.sex) 73 | except Exception as e: 74 | bot.reply_to(message, 'oooops') 75 | 76 | 77 | # Enable saving next step handlers to file "./.handlers-saves/step.save". 78 | # Delay=2 means that after any change in next step handlers (e.g. calling register_next_step_handler()) 79 | # saving will hapen after delay 2 seconds. 80 | bot.enable_save_next_step_handlers(delay=2) 81 | 82 | # Load next_step_handlers from save file (default "./.handlers-saves/step.save") 83 | # WARNING It will work only if enable_save_next_step_handlers was called! 84 | bot.load_next_step_handlers() 85 | 86 | bot.infinity_polling() 87 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_twisted_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is an example echo bot using webhook with Twisted network framework. 5 | # Updates are received with Twisted web server and processed in reactor thread pool. 6 | # Relevant docs: 7 | # https://twistedmatrix.com/documents/current/core/howto/reactor-basics.html 8 | # https://twistedmatrix.com/documents/current/web/howto/using-twistedweb.html 9 | 10 | import logging 11 | import telebot 12 | import json 13 | from twisted.internet import ssl, reactor 14 | from twisted.web.resource import Resource, ErrorPage 15 | from twisted.web.server import Site, Request 16 | 17 | API_TOKEN = '' 18 | 19 | WEBHOOK_HOST = '' 20 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 21 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 22 | 23 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 24 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 25 | 26 | # Quick'n'dirty SSL certificate generation: 27 | # 28 | # openssl genrsa -out webhook_pkey.pem 2048 29 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 30 | # 31 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 32 | # with the same value in you put in WEBHOOK_HOST 33 | 34 | WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) 35 | WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) 36 | 37 | logger = telebot.logger 38 | telebot.logger.setLevel(logging.INFO) 39 | bot = telebot.TeleBot(API_TOKEN) 40 | 41 | 42 | # Handle '/start' and '/help' 43 | @bot.message_handler(commands=['help', 'start']) 44 | def send_welcome(message): 45 | bot.reply_to(message, 46 | ("Hi there, I am EchoBot.\n" 47 | "I am here to echo your kind words back to you.")) 48 | 49 | 50 | # Handle all other messages 51 | @bot.message_handler(func=lambda message: True, content_types=['text']) 52 | def echo_message(message): 53 | bot.reply_to(message, message.text) 54 | 55 | 56 | # Remove webhook, it fails sometimes the set if there is a previous webhook 57 | bot.remove_webhook() 58 | 59 | # Set webhook 60 | bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 61 | certificate=open(WEBHOOK_SSL_CERT, 'r')) 62 | 63 | 64 | # Process webhook calls 65 | class WebhookHandler(Resource): 66 | isLeaf = True 67 | def render_POST(self, request: Request): 68 | request_body_dict = json.load(request.content) 69 | update = telebot.types.Update.de_json(request_body_dict) 70 | reactor.callInThread(lambda: bot.process_new_updates([update])) 71 | return b'' 72 | 73 | 74 | root = ErrorPage(403, 'Forbidden', '') 75 | root.putChild(API_TOKEN.encode(), WebhookHandler()) 76 | site = Site(root) 77 | sslcontext = ssl.DefaultOpenSSLContextFactory(WEBHOOK_SSL_PRIV, WEBHOOK_SSL_CERT) 78 | reactor.listenSSL(8443, site, sslcontext) 79 | reactor.run() 80 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/webhooks/webhook_starlette_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Asynchronous Telegram Echo Bot example. 4 | 5 | This is a simple bot that echoes each message that is received onto the chat. 6 | It uses the Starlette ASGI framework to receive updates via webhook requests. 7 | """ 8 | 9 | import uvicorn 10 | from starlette.applications import Starlette 11 | from starlette.requests import Request 12 | from starlette.responses import PlainTextResponse, Response 13 | from starlette.routing import Route 14 | from telebot.async_telebot import AsyncTeleBot 15 | from telebot.types import Message, Update 16 | 17 | API_TOKEN = "TOKEN" 18 | 19 | WEBHOOK_HOST = "" 20 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 21 | WEBHOOK_LISTEN = "0.0.0.0" 22 | WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate 23 | WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key 24 | WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}/telegram" 25 | WEBHOOK_SECRET_TOKEN = "SECRET_TOKEN" 26 | 27 | logger = telebot.logger 28 | telebot.logger.setLevel(logging.INFO) 29 | 30 | bot = AsyncTeleBot(token=API_TOKEN) 31 | 32 | # BOT HANDLERS 33 | @bot.message_handler(commands=["help", "start"]) 34 | async def send_welcome(message: Message): 35 | """ 36 | Handle '/start' and '/help' 37 | """ 38 | await bot.reply_to( 39 | message, 40 | ("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you."), 41 | ) 42 | 43 | 44 | @bot.message_handler(func=lambda _: True, content_types=["text"]) 45 | async def echo_message(message: Message): 46 | """ 47 | Handle all other messages 48 | """ 49 | await bot.reply_to(message, message.text) 50 | 51 | 52 | # WEBSERVER HANDLERS 53 | async def telegram(request: Request) -> Response: 54 | """Handle incoming Telegram updates.""" 55 | token_header_name = "X-Telegram-Bot-Api-Secret-Token" 56 | if request.headers.get(token_header_name) != WEBHOOK_SECRET_TOKEN: 57 | return PlainTextResponse("Forbidden", status_code=403) 58 | await bot.process_new_updates([Update.de_json(await request.json())]) 59 | return Response() 60 | 61 | 62 | async def startup() -> None: 63 | """Register webhook for telegram updates.""" 64 | webhook_info = await bot.get_webhook_info(30) 65 | if WEBHOOK_URL != webhook_info.url: 66 | logger.debug( 67 | f"updating webhook url, old: {webhook_info.url}, new: {WEBHOOK_URL}" 68 | ) 69 | if not await bot.set_webhook( 70 | url=WEBHOOK_URL, secret_token=WEBHOOK_SECRET_TOKEN 71 | ): 72 | raise RuntimeError("unable to set webhook") 73 | 74 | 75 | app = Starlette( 76 | routes=[ 77 | Route("/telegram", telegram, methods=["POST"]), 78 | ], 79 | on_startup=[startup], 80 | ) 81 | 82 | 83 | uvicorn.run( 84 | app, 85 | host=WEBHOOK_HOST, 86 | port=WEBHOOK_LISTEN, 87 | ssl_certfile=WEBHOOK_SSL_CERT, 88 | ssl_keyfile=WEBHOOK_SSL_PRIV, 89 | ) 90 | -------------------------------------------------------------------------------- /docs/source/locales/en/LC_MESSAGES/index.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../index.rst:8 22 | msgid "Welcome to pyTelegramBotAPI's documentation!" 23 | msgstr "" 24 | 25 | #: ../../index.rst:10 26 | msgid "Official documentation of pyTelegramBotAPI" 27 | msgstr "" 28 | 29 | #: ../../index.rst:10 30 | msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide" 31 | msgstr "" 32 | 33 | #: ../../index.rst:17 34 | msgid "TeleBot" 35 | msgstr "" 36 | 37 | #: ../../index.rst:18 38 | msgid "" 39 | "TeleBot is synchronous and asynchronous implementation of `Telegram Bot " 40 | "API `_." 41 | msgstr "" 42 | 43 | #: ../../index.rst:21 44 | msgid "Chats" 45 | msgstr "" 46 | 47 | #: ../../index.rst:22 48 | msgid "" 49 | "English chat: `Private chat " 50 | "`__" 51 | msgstr "" 52 | 53 | #: ../../index.rst:24 54 | msgid "" 55 | "Russian chat: `@pytelegrambotapi_talks_ru " 56 | "`__" 57 | msgstr "" 58 | 59 | #: ../../index.rst:26 60 | msgid "News: `@pyTelegramBotAPI `__" 61 | msgstr "" 62 | 63 | #: ../../index.rst:28 64 | msgid "Pypi: `Pypi `__" 65 | msgstr "" 66 | 67 | #: ../../index.rst:30 68 | msgid "" 69 | "Source: `Github repository " 70 | "`__" 71 | msgstr "" 72 | 73 | #: ../../index.rst:33 74 | msgid "Some features:" 75 | msgstr "" 76 | 77 | #: ../../index.rst:34 78 | msgid "Easy to learn and use." 79 | msgstr "" 80 | 81 | #: ../../index.rst:36 82 | msgid "Easy to understand." 83 | msgstr "" 84 | 85 | #: ../../index.rst:38 86 | msgid "Both sync and async." 87 | msgstr "" 88 | 89 | #: ../../index.rst:40 90 | msgid "Examples on features." 91 | msgstr "" 92 | 93 | #: ../../index.rst:42 94 | msgid "States" 95 | msgstr "" 96 | 97 | #: ../../index.rst:44 98 | msgid "And more..." 99 | msgstr "" 100 | 101 | #: ../../index.rst:47 102 | msgid "Content" 103 | msgstr "" 104 | 105 | #: ../../index.rst:63 106 | msgid "Indices and tables" 107 | msgstr "" 108 | 109 | #: ../../index.rst:65 110 | msgid ":ref:`genindex`" 111 | msgstr "" 112 | 113 | #: ../../index.rst:66 114 | msgid ":ref:`modindex`" 115 | msgstr "" 116 | 117 | #: ../../index.rst:67 118 | msgid ":ref:`search`" 119 | msgstr "" 120 | 121 | -------------------------------------------------------------------------------- /examples/callback_data_examples/simple_products_example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This Example will show you how to use CallbackData 4 | """ 5 | 6 | from telebot.callback_data import CallbackData, CallbackDataFilter 7 | from telebot import types, TeleBot 8 | from telebot.custom_filters import AdvancedCustomFilter 9 | 10 | API_TOKEN = '' 11 | PRODUCTS = [ 12 | {'id': '0', 'name': 'xiaomi mi 10', 'price': 400}, 13 | {'id': '1', 'name': 'samsung s20', 'price': 800}, 14 | {'id': '2', 'name': 'iphone 13', 'price': 1300} 15 | ] 16 | 17 | bot = TeleBot(API_TOKEN) 18 | products_factory = CallbackData('product_id', prefix='products') 19 | 20 | 21 | def products_keyboard(): 22 | return types.InlineKeyboardMarkup( 23 | keyboard=[ 24 | [ 25 | types.InlineKeyboardButton( 26 | text=product['name'], 27 | callback_data=products_factory.new(product_id=product["id"]) 28 | ) 29 | ] 30 | for product in PRODUCTS 31 | ] 32 | ) 33 | 34 | 35 | def back_keyboard(): 36 | return types.InlineKeyboardMarkup( 37 | keyboard=[ 38 | [ 39 | types.InlineKeyboardButton( 40 | text='⬅', 41 | callback_data='back' 42 | ) 43 | ] 44 | ] 45 | ) 46 | 47 | 48 | class ProductsCallbackFilter(AdvancedCustomFilter): 49 | key = 'config' 50 | 51 | def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 52 | return config.check(query=call) 53 | 54 | 55 | @bot.message_handler(commands=['products']) 56 | def products_command_handler(message: types.Message): 57 | bot.send_message(message.chat.id, 'Products:', reply_markup=products_keyboard()) 58 | 59 | 60 | # Only product with field - product_id = 2 61 | @bot.callback_query_handler(func=None, config=products_factory.filter(product_id='2')) 62 | def product_one_callback(call: types.CallbackQuery): 63 | bot.answer_callback_query(callback_query_id=call.id, text='Not available :(', show_alert=True) 64 | 65 | 66 | # Any other products 67 | @bot.callback_query_handler(func=None, config=products_factory.filter()) 68 | def products_callback(call: types.CallbackQuery): 69 | callback_data: dict = products_factory.parse(callback_data=call.data) 70 | product_id = int(callback_data['product_id']) 71 | product = PRODUCTS[product_id] 72 | 73 | text = f"Product name: {product['name']}\n" \ 74 | f"Product price: {product['price']}" 75 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, 76 | text=text, reply_markup=back_keyboard()) 77 | 78 | 79 | @bot.callback_query_handler(func=lambda c: c.data == 'back') 80 | def back_callback(call: types.CallbackQuery): 81 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, 82 | text='Products:', reply_markup=products_keyboard()) 83 | 84 | 85 | bot.add_custom_filter(ProductsCallbackFilter()) 86 | bot.infinity_polling() 87 | -------------------------------------------------------------------------------- /examples/inline_example.py: -------------------------------------------------------------------------------- 1 | # This example show how to write an inline mode telegram bot use pyTelegramBotAPI. 2 | import logging 3 | import sys 4 | import time 5 | 6 | import telebot 7 | from telebot import types 8 | 9 | API_TOKEN = '' 10 | 11 | bot = telebot.TeleBot(API_TOKEN) 12 | telebot.logger.setLevel(logging.DEBUG) 13 | 14 | 15 | @bot.inline_handler(lambda query: query.query == 'text') 16 | def query_text(inline_query): 17 | try: 18 | r = types.InlineQueryResultArticle('1', 'Result1', types.InputTextMessageContent('hi')) 19 | r2 = types.InlineQueryResultArticle('2', 'Result2', types.InputTextMessageContent('hi')) 20 | bot.answer_inline_query(inline_query.id, [r, r2]) 21 | except Exception as e: 22 | print(e) 23 | 24 | 25 | @bot.inline_handler(lambda query: query.query == 'photo1') 26 | def query_photo(inline_query): 27 | try: 28 | r = types.InlineQueryResultPhoto('1', 29 | 'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg', 30 | 'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg', 31 | input_message_content=types.InputTextMessageContent('hi')) 32 | r2 = types.InlineQueryResultPhoto('2', 33 | 'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg', 34 | 'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg') 35 | bot.answer_inline_query(inline_query.id, [r, r2], cache_time=1) 36 | except Exception as e: 37 | print(e) 38 | 39 | 40 | @bot.inline_handler(lambda query: query.query == 'video') 41 | def query_video(inline_query): 42 | try: 43 | r = types.InlineQueryResultVideo('1', 44 | 'https://github.com/eternnoir/pyTelegramBotAPI/blob/master/tests/test_data/test_video.mp4?raw=true', 45 | 'video/mp4', 46 | 'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg', 47 | 'Title' 48 | ) 49 | bot.answer_inline_query(inline_query.id, [r]) 50 | except Exception as e: 51 | print(e) 52 | 53 | 54 | @bot.inline_handler(lambda query: len(query.query) == 0) 55 | def default_query(inline_query): 56 | try: 57 | r = types.InlineQueryResultArticle('1', 'default', types.InputTextMessageContent('default')) 58 | bot.answer_inline_query(inline_query.id, [r]) 59 | except Exception as e: 60 | print(e) 61 | 62 | 63 | def main_loop(): 64 | bot.infinity_polling() 65 | while 1: 66 | time.sleep(3) 67 | 68 | 69 | if __name__ == '__main__': 70 | try: 71 | main_loop() 72 | except KeyboardInterrupt: 73 | print('\nExiting by user request.\n') 74 | sys.exit(0) 75 | -------------------------------------------------------------------------------- /examples/reply_keyboard_markup_example.py: -------------------------------------------------------------------------------- 1 | # This example shows you how to create a custom QWERTY keyboard using reply keyboard markup 2 | import telebot 3 | from telebot.types import ReplyKeyboardMarkup, KeyboardButton 4 | 5 | TOKEN = "" 6 | bot = telebot.TeleBot(TOKEN) 7 | 8 | keys = ["1","2","3","4","5","6","7","8","9","0","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m"] 9 | symbols = ["1","2","3","4","5","6","7","8","9","0","!","@","#","$","%","^","&","*","(",")","\'","\"","/","\\",",",".",";",":"] 10 | 11 | def keyboard(key_type="Normal"): 12 | markup = ReplyKeyboardMarkup(row_width=10) 13 | if key_type == "Normal": 14 | row = [KeyboardButton(x) for x in keys[:10]] 15 | markup.add(*row) 16 | row = [KeyboardButton(x) for x in keys[10:20]] 17 | markup.add(*row) 18 | row = [KeyboardButton(x) for x in keys[20:29]] 19 | markup.add(*row) 20 | row = [KeyboardButton(x) for x in keys[29:]] 21 | markup.add(*row) 22 | markup.add(KeyboardButton("Caps Lock"),KeyboardButton("Symbols"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done")) 23 | elif key_type == "Symbols": 24 | row = [KeyboardButton(x) for x in symbols[:10]] 25 | markup.add(*row) 26 | row = [KeyboardButton(x) for x in symbols[10:20]] 27 | markup.add(*row) 28 | row = [KeyboardButton(x) for x in symbols[20:]] 29 | markup.add(*row) 30 | markup.add(KeyboardButton("Caps Lock"),KeyboardButton("Normal"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done")) 31 | else: 32 | row = [KeyboardButton(x.upper()) for x in keys[:10]] 33 | markup.add(*row) 34 | row = [KeyboardButton(x.upper()) for x in keys[10:20]] 35 | markup.add(*row) 36 | row = [KeyboardButton(x.upper()) for x in keys[20:29]] 37 | markup.add(*row) 38 | row = [KeyboardButton(x.upper()) for x in keys[29:]] 39 | markup.add(*row) 40 | markup.add(KeyboardButton("Normal"),KeyboardButton("Symbols"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done")) 41 | return markup 42 | 43 | @bot.message_handler(commands=["start"]) 44 | def start_message(message): 45 | bot.send_message(message.chat.id,"You can use the keyboard",reply_markup=keyboard()) 46 | 47 | @bot.message_handler(func=lambda message:True) 48 | def all_messages(message): 49 | if message.text == "✅Done": 50 | markup = telebot.types.ReplyKeyboardRemove() 51 | bot.send_message(message.from_user.id,"Done with Keyboard",reply_markup=markup) 52 | elif message.text == "Symbols": 53 | bot.send_message(message.from_user.id,"Special characters",reply_markup=keyboard("Symbols")) 54 | elif message.text == "Normal": 55 | bot.send_message(message.from_user.id,"Normal Keyboard",reply_markup=keyboard("Normal")) 56 | elif message.text == "Caps Lock": 57 | bot.send_message(message.from_user.id,"Caps Lock",reply_markup=keyboard("Caps")) 58 | elif message.text == "🔙Delete": 59 | bot.delete_message(message.from_user.id,message.message_id) 60 | else: 61 | bot.send_message(message.chat.id,message.text) 62 | 63 | bot.infinity_polling() 64 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/callback_data_examples/advanced_calendar_example/keyboards.py: -------------------------------------------------------------------------------- 1 | import calendar 2 | from datetime import date, timedelta 3 | 4 | from filters import calendar_factory, calendar_zoom 5 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton 6 | 7 | EMTPY_FIELD = '1' 8 | WEEK_DAYS = [calendar.day_abbr[i] for i in range(7)] 9 | MONTHS = [(i, calendar.month_name[i]) for i in range(1, 13)] 10 | 11 | 12 | def generate_calendar_days(year: int, month: int): 13 | keyboard = InlineKeyboardMarkup(row_width=7) 14 | today = date.today() 15 | 16 | keyboard.add( 17 | InlineKeyboardButton( 18 | text=date(year=year, month=month, day=1).strftime('%b %Y'), 19 | callback_data=EMTPY_FIELD 20 | ) 21 | ) 22 | keyboard.add(*[ 23 | InlineKeyboardButton( 24 | text=day, 25 | callback_data=EMTPY_FIELD 26 | ) 27 | for day in WEEK_DAYS 28 | ]) 29 | 30 | for week in calendar.Calendar().monthdayscalendar(year=year, month=month): 31 | week_buttons = [] 32 | for day in week: 33 | day_name = ' ' 34 | if day == today.day and today.year == year and today.month == month: 35 | day_name = '🔘' 36 | elif day != 0: 37 | day_name = str(day) 38 | week_buttons.append( 39 | InlineKeyboardButton( 40 | text=day_name, 41 | callback_data=EMTPY_FIELD 42 | ) 43 | ) 44 | keyboard.add(*week_buttons) 45 | 46 | previous_date = date(year=year, month=month, day=1) - timedelta(days=1) 47 | next_date = date(year=year, month=month, day=1) + timedelta(days=31) 48 | 49 | keyboard.add( 50 | InlineKeyboardButton( 51 | text='Previous month', 52 | callback_data=calendar_factory.new(year=previous_date.year, month=previous_date.month) 53 | ), 54 | InlineKeyboardButton( 55 | text='Zoom out', 56 | callback_data=calendar_zoom.new(year=year) 57 | ), 58 | InlineKeyboardButton( 59 | text='Next month', 60 | callback_data=calendar_factory.new(year=next_date.year, month=next_date.month) 61 | ), 62 | ) 63 | 64 | return keyboard 65 | 66 | 67 | def generate_calendar_months(year: int): 68 | keyboard = InlineKeyboardMarkup(row_width=3) 69 | keyboard.add( 70 | InlineKeyboardButton( 71 | text=date(year=year, month=1, day=1).strftime('Year %Y'), 72 | callback_data=EMTPY_FIELD 73 | ) 74 | ) 75 | keyboard.add(*[ 76 | InlineKeyboardButton( 77 | text=month, 78 | callback_data=calendar_factory.new(year=year, month=month_number) 79 | ) 80 | for month_number, month in MONTHS 81 | ]) 82 | keyboard.add( 83 | InlineKeyboardButton( 84 | text='Previous year', 85 | callback_data=calendar_zoom.new(year=year - 1) 86 | ), 87 | InlineKeyboardButton( 88 | text='Next year', 89 | callback_data=calendar_zoom.new(year=year + 1) 90 | ) 91 | ) 92 | return keyboard 93 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/callback_data_examples/simple_products_example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This Example will show you how to use CallbackData 4 | """ 5 | 6 | from telebot.callback_data import CallbackData, CallbackDataFilter 7 | from telebot import types 8 | from telebot.async_telebot import AsyncTeleBot 9 | from telebot.asyncio_filters import AdvancedCustomFilter 10 | 11 | API_TOKEN = 'TOKEN' 12 | PRODUCTS = [ 13 | {'id': '0', 'name': 'xiaomi mi 10', 'price': 400}, 14 | {'id': '1', 'name': 'samsung s20', 'price': 800}, 15 | {'id': '2', 'name': 'iphone 13', 'price': 1300} 16 | ] 17 | 18 | bot = AsyncTeleBot(API_TOKEN) 19 | products_factory = CallbackData('product_id', prefix='products') 20 | 21 | 22 | def products_keyboard(): 23 | return types.InlineKeyboardMarkup( 24 | keyboard=[ 25 | [ 26 | types.InlineKeyboardButton( 27 | text=product['name'], 28 | callback_data=products_factory.new(product_id=product["id"]) 29 | ) 30 | ] 31 | for product in PRODUCTS 32 | ] 33 | ) 34 | 35 | 36 | def back_keyboard(): 37 | return types.InlineKeyboardMarkup( 38 | keyboard=[ 39 | [ 40 | types.InlineKeyboardButton( 41 | text='⬅', 42 | callback_data='back' 43 | ) 44 | ] 45 | ] 46 | ) 47 | 48 | 49 | class ProductsCallbackFilter(AdvancedCustomFilter): 50 | key = 'config' 51 | 52 | async def check(self, call: types.CallbackQuery, config: CallbackDataFilter): 53 | return config.check(query=call) 54 | 55 | 56 | @bot.message_handler(commands=['products']) 57 | async def products_command_handler(message: types.Message): 58 | await bot.send_message(message.chat.id, 'Products:', reply_markup=products_keyboard()) 59 | 60 | 61 | # Only product with field - product_id = 2 62 | @bot.callback_query_handler(func=None, config=products_factory.filter(product_id='2')) 63 | async def product_one_callback(call: types.CallbackQuery): 64 | await bot.answer_callback_query(callback_query_id=call.id, text='Not available :(', show_alert=True) 65 | 66 | 67 | # Any other products 68 | @bot.callback_query_handler(func=None, config=products_factory.filter()) 69 | async def products_callback(call: types.CallbackQuery): 70 | callback_data: dict = products_factory.parse(callback_data=call.data) 71 | product_id = int(callback_data['product_id']) 72 | product = PRODUCTS[product_id] 73 | 74 | text = f"Product name: {product['name']}\n" \ 75 | f"Product price: {product['price']}" 76 | await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, 77 | text=text, reply_markup=back_keyboard()) 78 | 79 | 80 | @bot.callback_query_handler(func=lambda c: c.data == 'back') 81 | async def back_callback(call: types.CallbackQuery): 82 | await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, 83 | text='Products:', reply_markup=products_keyboard()) 84 | 85 | 86 | bot.add_custom_filter(ProductsCallbackFilter()) 87 | import asyncio 88 | asyncio.run(bot.polling()) 89 | -------------------------------------------------------------------------------- /examples/callback_data_examples/advanced_calendar_example/keyboards.py: -------------------------------------------------------------------------------- 1 | import calendar 2 | from datetime import date, timedelta 3 | 4 | from examples.callback_data_examples.advanced_calendar_example.filters import calendar_factory, calendar_zoom 5 | from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton 6 | 7 | EMTPY_FIELD = '1' 8 | WEEK_DAYS = [calendar.day_abbr[i] for i in range(7)] 9 | MONTHS = [(i, calendar.month_name[i]) for i in range(1, 13)] 10 | 11 | 12 | def generate_calendar_days(year: int, month: int): 13 | keyboard = InlineKeyboardMarkup(row_width=7) 14 | today = date.today() 15 | 16 | keyboard.add( 17 | InlineKeyboardButton( 18 | text=date(year=year, month=month, day=1).strftime('%b %Y'), 19 | callback_data=EMTPY_FIELD 20 | ) 21 | ) 22 | keyboard.add(*[ 23 | InlineKeyboardButton( 24 | text=day, 25 | callback_data=EMTPY_FIELD 26 | ) 27 | for day in WEEK_DAYS 28 | ]) 29 | 30 | for week in calendar.Calendar().monthdayscalendar(year=year, month=month): 31 | week_buttons = [] 32 | for day in week: 33 | day_name = ' ' 34 | if day == today.day and today.year == year and today.month == month: 35 | day_name = '🔘' 36 | elif day != 0: 37 | day_name = str(day) 38 | week_buttons.append( 39 | InlineKeyboardButton( 40 | text=day_name, 41 | callback_data=EMTPY_FIELD 42 | ) 43 | ) 44 | keyboard.add(*week_buttons) 45 | 46 | previous_date = date(year=year, month=month, day=1) - timedelta(days=1) 47 | next_date = date(year=year, month=month, day=1) + timedelta(days=31) 48 | 49 | keyboard.add( 50 | InlineKeyboardButton( 51 | text='Previous month', 52 | callback_data=calendar_factory.new(year=previous_date.year, month=previous_date.month) 53 | ), 54 | InlineKeyboardButton( 55 | text='Zoom out', 56 | callback_data=calendar_zoom.new(year=year) 57 | ), 58 | InlineKeyboardButton( 59 | text='Next month', 60 | callback_data=calendar_factory.new(year=next_date.year, month=next_date.month) 61 | ), 62 | ) 63 | 64 | return keyboard 65 | 66 | 67 | def generate_calendar_months(year: int): 68 | keyboard = InlineKeyboardMarkup(row_width=3) 69 | keyboard.add( 70 | InlineKeyboardButton( 71 | text=date(year=year, month=1, day=1).strftime('Year %Y'), 72 | callback_data=EMTPY_FIELD 73 | ) 74 | ) 75 | keyboard.add(*[ 76 | InlineKeyboardButton( 77 | text=month, 78 | callback_data=calendar_factory.new(year=year, month=month_number) 79 | ) 80 | for month_number, month in MONTHS 81 | ]) 82 | keyboard.add( 83 | InlineKeyboardButton( 84 | text='Previous year', 85 | callback_data=calendar_zoom.new(year=year - 1) 86 | ), 87 | InlineKeyboardButton( 88 | text='Next year', 89 | callback_data=calendar_zoom.new(year=year + 1) 90 | ) 91 | ) 92 | return keyboard 93 | -------------------------------------------------------------------------------- /examples/deep_linking.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This example shows how to implement deep linking (https://core.telegram.org/bots#deep-linking) 4 | # with the pyTelegramBotAPI. 5 | # Note: This is not a working, production-ready sample. 6 | # 7 | # In this example we are connecting a user account on a website with a Telegram bot. 8 | # Implementing this will enable you to push notifications (and other content) to your users' Telegram account. 9 | # In this explanation the word 'database' can refer to any form of key-value storage. 10 | # The deep linking explained: 11 | # 12 | # 1. Let the user log in on an actual website with actual username-password authentication. 13 | # 14 | # 2. Generate a unique hashcode (we will call it unique_code) 15 | # 16 | # 3. Save unique_code->username to the database. 17 | # 18 | # 4. Show the user the URL https://telegram.me/YOURBOTNAME?start=unique_code 19 | # 20 | # 5. Now as soon as the user opens this URL in Telegram and presses 'Start', 21 | # your bot will receive a text message containing '/start unique_code', 22 | # where unique_code is of course replaced by the actual hashcode. 23 | # 24 | # 6. Let the bot retrieve the username by querying the database for unique_code. 25 | # 26 | # 7. Save chat_id->username to the database. 27 | # 28 | # 8. Now when your bot receives another message, it can query message.chat.id in the database 29 | # to check if the message is from this specific user. (And handle accordingly) or 30 | # you can push messages to the user using his chat id. 31 | # 32 | # Steps 1 to 4 will have to be implemented in a web server, using a language such as PHP, Python, C# or Java. These 33 | # steps are not shown here. Only steps 5 to 7 are illustrated, some in pseudo-code, with this example. 34 | 35 | import telebot 36 | 37 | bot = telebot.TeleBot('TOKEN') 38 | 39 | 40 | def extract_unique_code(text): 41 | # Extracts the unique_code from the sent /start command. 42 | return text.split()[1] if len(text.split()) > 1 else None 43 | 44 | 45 | def in_storage(unique_code): 46 | # (pseudo-code) Should check if a unique code exists in storage 47 | return True 48 | 49 | 50 | def get_username_from_storage(unique_code): 51 | # (pseudo-code) Does a query to the storage, retrieving the associated username 52 | # Should be replaced by a real database-lookup. 53 | return "ABC" if in_storage(unique_code) else None 54 | 55 | 56 | def save_chat_id(chat_id, username): 57 | # (pseudo-code) Save the chat_id->username to storage 58 | # Should be replaced by a real database query. 59 | pass 60 | 61 | 62 | @bot.message_handler(commands=['start']) 63 | def send_welcome(message): 64 | unique_code = extract_unique_code(message.text) 65 | if unique_code: # if the '/start' command contains a unique_code 66 | username = get_username_from_storage(unique_code) 67 | if username: # if the username exists in our database 68 | save_chat_id(message.chat.id, username) 69 | reply = "Hello {0}, how are you?".format(username) 70 | else: 71 | reply = "I have no clue who you are..." 72 | else: 73 | reply = "Please visit me via a provided URL from the website." 74 | bot.reply_to(message, reply) 75 | 76 | 77 | bot.infinity_polling() 78 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_cherrypy_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a simple echo bot using decorators and webhook with CherryPy 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | import logging 8 | 9 | import cherrypy 10 | 11 | import telebot 12 | 13 | API_TOKEN = '' 14 | 15 | WEBHOOK_HOST = '' 16 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 17 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 18 | 19 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 20 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 21 | 22 | # Quick'n'dirty SSL certificate generation: 23 | # 24 | # openssl genrsa -out webhook_pkey.pem 2048 25 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 26 | # 27 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 28 | # with the same value in you put in WEBHOOK_HOST 29 | 30 | WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) 31 | WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) 32 | 33 | logger = telebot.logger 34 | telebot.logger.setLevel(logging.INFO) 35 | 36 | bot = telebot.TeleBot(API_TOKEN) 37 | 38 | 39 | # WebhookServer, process webhook calls 40 | class WebhookServer(object): 41 | @cherrypy.expose 42 | def index(self): 43 | if 'content-length' in cherrypy.request.headers and \ 44 | 'content-type' in cherrypy.request.headers and \ 45 | cherrypy.request.headers['content-type'] == 'application/json': 46 | length = int(cherrypy.request.headers['content-length']) 47 | json_string = cherrypy.request.body.read(length).decode("utf-8") 48 | update = telebot.types.Update.de_json(json_string) 49 | bot.process_new_updates([update]) 50 | return '' 51 | else: 52 | raise cherrypy.HTTPError(403) 53 | 54 | 55 | # Handle '/start' and '/help' 56 | @bot.message_handler(commands=['help', 'start']) 57 | def send_welcome(message): 58 | bot.reply_to(message, 59 | ("Hi there, I am EchoBot.\n" 60 | "I am here to echo your kind words back to you.")) 61 | 62 | 63 | # Handle all other messages 64 | @bot.message_handler(func=lambda message: True, content_types=['text']) 65 | def echo_message(message): 66 | bot.reply_to(message, message.text) 67 | 68 | 69 | # Remove webhook, it fails sometimes the set if there is a previous webhook 70 | bot.remove_webhook() 71 | 72 | # Set webhook 73 | bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 74 | certificate=open(WEBHOOK_SSL_CERT, 'r')) 75 | 76 | # Disable CherryPy requests log 77 | access_log = cherrypy.log.access_log 78 | for handler in tuple(access_log.handlers): 79 | access_log.removeHandler(handler) 80 | 81 | # Start cherrypy server 82 | cherrypy.config.update({ 83 | 'server.socket_host' : WEBHOOK_LISTEN, 84 | 'server.socket_port' : WEBHOOK_PORT, 85 | 'server.ssl_module' : 'builtin', 86 | 'server.ssl_certificate': WEBHOOK_SSL_CERT, 87 | 'server.ssl_private_key': WEBHOOK_SSL_PRIV 88 | }) 89 | 90 | cherrypy.quickstart(WebhookServer(), WEBHOOK_URL_PATH, {'/': {}}) 91 | -------------------------------------------------------------------------------- /examples/telebot_bot/telebot_bot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # This bot was made specifically for the pyTelegramAPI Telegram chat, 3 | # and goes by the name 'TeleBot (@pyTeleBot)'. Join our group to talk to him! 4 | # WARNING: Tested with Python 2.7 5 | 6 | import os 7 | 8 | import telebot 9 | 10 | text_messages = { 11 | 'welcome': 12 | u'Please welcome {name}!\n\n' 13 | u'This chat is intended for questions about and discussion of the pyTelegramBotAPI.\n' 14 | u'To enable group members to answer your questions fast and accurately, please make sure to study the ' 15 | u'project\'s documentation (https://github.com/eternnoir/pyTelegramBotAPI/blob/master/README.md) and the ' 16 | u'examples (https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples) first.\n\n' 17 | u'I hope you enjoy your stay here!', 18 | 19 | 'info': 20 | u'My name is TeleBot,\n' 21 | u'I am a bot that assists these wonderful bot-creating people of this bot library group chat.\n' 22 | u'Also, I am still under development. Please improve my functionality by making a pull request! ' 23 | u'Suggestions are also welcome, just drop them in this group chat!', 24 | 25 | 'wrong_chat': 26 | u'Hi there!\nThanks for trying me out. However, this bot can only be used in the pyTelegramAPI group chat.\n' 27 | u'Join us!\n\n' 28 | u'https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b' 29 | } 30 | 31 | if "TELEBOT_BOT_TOKEN" not in os.environ or "GROUP_CHAT_ID" not in os.environ: 32 | raise AssertionError("Please configure TELEBOT_BOT_TOKEN and GROUP_CHAT_ID as environment variables") 33 | 34 | bot = telebot.AsyncTeleBot(os.environ["TELEBOT_BOT_TOKEN"]) 35 | GROUP_CHAT_ID = int(os.environ["GROUP_CHAT_ID"]) 36 | 37 | 38 | def is_api_group(chat_id): 39 | return chat_id == GROUP_CHAT_ID 40 | 41 | 42 | @bot.message_handler(func=lambda m: True, content_types=['new_chat_participant']) 43 | def on_user_joins(message): 44 | if not is_api_group(message.chat.id): 45 | return 46 | 47 | name = message.new_chat_participant.first_name 48 | if hasattr(message.new_chat_participant, 'last_name') and message.new_chat_participant.last_name is not None: 49 | name += u" {}".format(message.new_chat_participant.last_name) 50 | 51 | if hasattr(message.new_chat_participant, 'username') and message.new_chat_participant.username is not None: 52 | name += u" (@{})".format(message.new_chat_participant.username) 53 | 54 | bot.reply_to(message, text_messages['welcome'].format(name=name)) 55 | 56 | 57 | @bot.message_handler(commands=['info', 'help']) 58 | def on_info(message): 59 | if not is_api_group(message.chat.id): 60 | bot.reply_to(message, text_messages['wrong_chat']) 61 | return 62 | 63 | bot.reply_to(message, text_messages['info']) 64 | 65 | 66 | @bot.message_handler(commands=["ping"]) 67 | def on_ping(message): 68 | bot.reply_to(message, "Still alive and kicking!") 69 | 70 | 71 | @bot.message_handler(commands=['start']) 72 | def on_start(message): 73 | if not is_api_group(message.chat.id): 74 | bot.reply_to(message, text_messages['wrong_chat']) 75 | return 76 | 77 | 78 | def listener(messages): 79 | for m in messages: 80 | print(str(m)) 81 | 82 | 83 | bot.set_update_listener(listener) 84 | bot.infinity_polling() 85 | -------------------------------------------------------------------------------- /examples/asynchronous_telebot/custom_states.py: -------------------------------------------------------------------------------- 1 | from telebot import asyncio_filters 2 | from telebot.async_telebot import AsyncTeleBot 3 | 4 | # list of storages, you can use any storage 5 | from telebot.asyncio_storage import StateMemoryStorage 6 | 7 | # new feature for states. 8 | from telebot.asyncio_handler_backends import State, StatesGroup 9 | 10 | # default state storage is statememorystorage 11 | bot = AsyncTeleBot('TOKEN', state_storage=StateMemoryStorage()) 12 | 13 | 14 | # Just create different statesgroup 15 | class MyStates(StatesGroup): 16 | name = State() # statesgroup should contain states 17 | surname = State() 18 | age = State() 19 | 20 | 21 | 22 | # set_state -> sets a new state 23 | # delete_state -> delets state if exists 24 | # get_state -> returns state if exists 25 | 26 | 27 | @bot.message_handler(commands=['start']) 28 | async def start_ex(message): 29 | """ 30 | Start command. Here we are starting state 31 | """ 32 | await bot.set_state(message.from_user.id, MyStates.name, message.chat.id) 33 | await bot.send_message(message.chat.id, 'Hi, write me a name') 34 | 35 | 36 | 37 | @bot.message_handler(state="*", commands='cancel') 38 | async def any_state(message): 39 | """ 40 | Cancel state 41 | """ 42 | await bot.send_message(message.chat.id, "Your state was cancelled.") 43 | await bot.delete_state(message.from_user.id, message.chat.id) 44 | 45 | @bot.message_handler(state=MyStates.name) 46 | async def name_get(message): 47 | """ 48 | State 1. Will process when user's state is MyStates.name. 49 | """ 50 | await bot.send_message(message.chat.id, f'Now write me a surname') 51 | await bot.set_state(message.from_user.id, MyStates.surname, message.chat.id) 52 | async with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 53 | data['name'] = message.text 54 | 55 | 56 | @bot.message_handler(state=MyStates.surname) 57 | async def ask_age(message): 58 | """ 59 | State 2. Will process when user's state is MyStates.surname. 60 | """ 61 | await bot.send_message(message.chat.id, "What is your age?") 62 | await bot.set_state(message.from_user.id, MyStates.age, message.chat.id) 63 | async with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 64 | data['surname'] = message.text 65 | 66 | # result 67 | @bot.message_handler(state=MyStates.age, is_digit=True) 68 | async def ready_for_answer(message): 69 | """ 70 | State 3. Will process when user's state is MyStates.age. 71 | """ 72 | async with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 73 | await bot.send_message(message.chat.id, "Ready, take a look:\nName: {name}\nSurname: {surname}\nAge: {age}".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html") 74 | await bot.delete_state(message.from_user.id, message.chat.id) 75 | 76 | #incorrect number 77 | @bot.message_handler(state=MyStates.age, is_digit=False) 78 | async def age_incorrect(message): 79 | """ 80 | Will process for wrong input when state is MyState.age 81 | """ 82 | await bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number') 83 | 84 | # register filters 85 | 86 | bot.add_custom_filter(asyncio_filters.StateFilter(bot)) 87 | bot.add_custom_filter(asyncio_filters.IsDigitFilter()) 88 | 89 | 90 | import asyncio 91 | asyncio.run(bot.polling()) -------------------------------------------------------------------------------- /examples/asynchronous_telebot/webhooks/async_webhook_aiohttp_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is an async echo bot using decorators and webhook with aiohttp 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | import logging 8 | import ssl 9 | import asyncio 10 | from aiohttp import web 11 | import telebot 12 | from telebot.async_telebot import AsyncTeleBot 13 | 14 | API_TOKEN = '' 15 | WEBHOOK_HOST = '' 16 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 17 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 18 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 19 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 20 | WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) 21 | WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) 22 | 23 | # Quick'n'dirty SSL certificate generation: 24 | # 25 | # openssl genrsa -out webhook_pkey.pem 2048 26 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 27 | # 28 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 29 | # with the same value in you put in WEBHOOK_HOST 30 | 31 | logger = telebot.logger 32 | telebot.logger.setLevel(logging.INFO) 33 | bot = AsyncTeleBot(API_TOKEN) 34 | 35 | 36 | # Process webhook calls 37 | async def handle(request): 38 | if request.match_info.get('token') == bot.token: 39 | request_body_dict = await request.json() 40 | update = telebot.types.Update.de_json(request_body_dict) 41 | asyncio.ensure_future(bot.process_new_updates([update])) 42 | return web.Response() 43 | else: 44 | return web.Response(status=403) 45 | 46 | 47 | # Handle '/start' and '/help' 48 | @bot.message_handler(commands=['help', 'start']) 49 | async def send_welcome(message): 50 | await bot.reply_to(message, 51 | ("Hi there, I am EchoBot.\n" 52 | "I am here to echo your kind words back to you.")) 53 | 54 | 55 | # Handle all other messages 56 | @bot.message_handler(func=lambda message: True, content_types=['text']) 57 | async def echo_message(message): 58 | await bot.reply_to(message, message.text) 59 | 60 | 61 | # Remove webhook and closing session before exiting 62 | async def shutdown(app): 63 | logger.info('Shutting down: removing webhook') 64 | await bot.remove_webhook() 65 | logger.info('Shutting down: closing session') 66 | await bot.close_session() 67 | 68 | 69 | async def setup(): 70 | # Remove webhook, it fails sometimes the set if there is a previous webhook 71 | logger.info('Starting up: removing old webhook') 72 | await bot.remove_webhook() 73 | # Set webhook 74 | logger.info('Starting up: setting webhook') 75 | await bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 76 | certificate=open(WEBHOOK_SSL_CERT, 'r')) 77 | app = web.Application() 78 | app.router.add_post('/{token}/', handle) 79 | app.on_cleanup.append(shutdown) 80 | return app 81 | 82 | 83 | if __name__ == '__main__': 84 | # Build ssl context 85 | context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 86 | context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV) 87 | # Start aiohttp server 88 | web.run_app( 89 | setup(), 90 | host=WEBHOOK_LISTEN, 91 | port=WEBHOOK_PORT, 92 | ssl_context=context, 93 | ) 94 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_tornado_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This example shows webhook echo bot with Tornado web framework 5 | # Documenation to Tornado: http://tornadoweb.org 6 | 7 | import signal 8 | from typing import Optional, Awaitable 9 | 10 | import tornado.httpserver 11 | import tornado.ioloop 12 | import tornado.options 13 | import tornado.web 14 | 15 | import telebot 16 | 17 | API_TOKEN = '' 18 | WEBHOOK_CERT = "./cert.pem" 19 | WEBHOOK_PKEY = "./pkey.pem" 20 | WEBHOOK_HOST = "" 21 | WEBHOOK_SECRET = " Optional[Awaitable[None]]: 38 | pass 39 | 40 | def get(self): 41 | self.write("Hi! This is webhook example!") 42 | self.finish() 43 | 44 | 45 | class WebhookServ(tornado.web.RequestHandler): 46 | def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: 47 | pass 48 | 49 | def get(self): 50 | self.write("What are you doing here?") 51 | self.finish() 52 | 53 | def post(self): 54 | if "Content-Length" in self.request.headers and \ 55 | "Content-Type" in self.request.headers and \ 56 | self.request.headers['Content-Type'] == "application/json": 57 | 58 | # length = int(self.request.headers['Content-Length']) 59 | json_data = self.request.body.decode("utf-8") 60 | update = telebot.types.Update.de_json(json_data) 61 | bot.process_new_updates([update]) 62 | self.write("") 63 | self.finish() 64 | else: 65 | self.write("What are you doing here?") 66 | self.finish() 67 | 68 | 69 | tornado.options.define("port", default=WEBHOOK_PORT, help="run on the given port", type=int) 70 | is_closing = False 71 | 72 | 73 | def signal_handler(signum, frame): 74 | global is_closing 75 | print("Exiting...") 76 | is_closing = True 77 | 78 | 79 | def try_exit(): 80 | global is_closing 81 | if is_closing: 82 | # clean up here 83 | tornado.ioloop.IOLoop.instance().stop() 84 | print("Exit success!") 85 | 86 | 87 | # Handle '/start' and '/help' 88 | @bot.message_handler(commands=['help', 'start']) 89 | def send_welcome(message): 90 | bot.reply_to(message, 91 | ("Hi there, I am EchoBot.\n" 92 | "I am here to echo your kind words back to you.")) 93 | 94 | 95 | bot.remove_webhook() 96 | bot.set_webhook(url=WEBHOOK_URL_BASE, 97 | certificate=open(WEBHOOK_CERT, 'r')) 98 | tornado.options.options.logging = None 99 | tornado.options.parse_command_line() 100 | signal.signal(signal.SIGINT, signal_handler) 101 | application = tornado.web.Application([ 102 | (r"/", Root), 103 | (r"/" + WEBHOOK_SECRET, WebhookServ) 104 | ]) 105 | 106 | http_server = tornado.httpserver.HTTPServer(application, ssl_options={ 107 | "certfile": WEBHOOK_CERT, 108 | "keyfile" : WEBHOOK_PKEY, 109 | }) 110 | http_server.listen(tornado.options.options.port) 111 | tornado.ioloop.PeriodicCallback(try_exit, 100).start() 112 | tornado.ioloop.IOLoop.instance().start() 113 | -------------------------------------------------------------------------------- /examples/webhook_examples/webhook_cpython_echo_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is a simple echo bot using decorators and webhook with BaseHTTPServer 5 | # It echoes any incoming text messages and does not use the polling method. 6 | 7 | try: 8 | # Python 2 9 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 10 | except ImportError: 11 | # Python 3 12 | from http.server import BaseHTTPRequestHandler, HTTPServer 13 | 14 | import logging 15 | import ssl 16 | 17 | import telebot 18 | 19 | API_TOKEN = '' 20 | 21 | WEBHOOK_HOST = '' 22 | WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') 23 | WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr 24 | 25 | WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate 26 | WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key 27 | 28 | # Quick'n'dirty SSL certificate generation: 29 | # 30 | # openssl genrsa -out webhook_pkey.pem 2048 31 | # openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem 32 | # 33 | # When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply 34 | # with the same value in you put in WEBHOOK_HOST 35 | 36 | WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) 37 | WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) 38 | 39 | logger = telebot.logger 40 | telebot.logger.setLevel(logging.INFO) 41 | 42 | bot = telebot.TeleBot(API_TOKEN) 43 | 44 | 45 | # WebhookHandler, process webhook calls 46 | class WebhookHandler(BaseHTTPRequestHandler): 47 | server_version = "WebhookHandler/1.0" 48 | 49 | def do_HEAD(self): 50 | self.send_response(200) 51 | self.end_headers() 52 | 53 | def do_GET(self): 54 | self.send_response(200) 55 | self.end_headers() 56 | 57 | def do_POST(self): 58 | if self.path == WEBHOOK_URL_PATH and \ 59 | 'content-type' in self.headers and \ 60 | 'content-length' in self.headers and \ 61 | self.headers['content-type'] == 'application/json': 62 | json_string = self.rfile.read(int(self.headers['content-length'])) 63 | 64 | self.send_response(200) 65 | self.end_headers() 66 | 67 | update = telebot.types.Update.de_json(json_string) 68 | bot.process_new_messages([update.message]) 69 | else: 70 | self.send_error(403) 71 | self.end_headers() 72 | 73 | 74 | # Handle '/start' and '/help' 75 | @bot.message_handler(commands=['help', 'start']) 76 | def send_welcome(message): 77 | bot.reply_to(message, 78 | ("Hi there, I am EchoBot.\n" 79 | "I am here to echo your kind words back to you.")) 80 | 81 | 82 | # Handle all other messages 83 | @bot.message_handler(func=lambda message: True, content_types=['text']) 84 | def echo_message(message): 85 | bot.reply_to(message, message.text) 86 | 87 | 88 | # Remove webhook, it fails sometimes the set if there is a previous webhook 89 | #bot.remove_webhook() 90 | 91 | # Set webhook 92 | # Beacuse telegram bot api server will check webhook server is alive. 93 | # Here we need set webhook after server started manually. 94 | #bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, 95 | # certificate=open(WEBHOOK_SSL_CERT, 'r')) 96 | 97 | # Start server 98 | httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT), 99 | WebhookHandler) 100 | 101 | httpd.socket = ssl.wrap_socket(httpd.socket, 102 | certfile=WEBHOOK_SSL_CERT, 103 | keyfile=WEBHOOK_SSL_PRIV, 104 | server_side=True) 105 | 106 | httpd.serve_forever() 107 | -------------------------------------------------------------------------------- /docs/source/locales/ru/LC_MESSAGES/index.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../index.rst:8 22 | msgid "Welcome to pyTelegramBotAPI's documentation!" 23 | msgstr "Добро пожаловать в документацию pyTelegramBotAPI!" 24 | 25 | #: ../../index.rst:10 26 | msgid "Official documentation of pyTelegramBotAPI" 27 | msgstr "Официальная документация pyTelegramBotAPI" 28 | 29 | #: ../../index.rst:10 30 | msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide" 31 | msgstr "ptba, pytba, pyTelegramBotAPI, документация, гайд" 32 | 33 | #: ../../index.rst:17 34 | msgid "TeleBot" 35 | msgstr "" 36 | 37 | #: ../../index.rst:18 38 | msgid "" 39 | "TeleBot is synchronous and asynchronous implementation of `Telegram Bot " 40 | "API `_." 41 | msgstr "" 42 | "TeleBot это синхронная и асинхронная реализация `Telegram Bot " 43 | "API `_." 44 | 45 | #: ../../index.rst:21 46 | msgid "Chats" 47 | msgstr "Чаты" 48 | 49 | #: ../../index.rst:22 50 | msgid "" 51 | "English chat: `Private chat " 52 | "`__" 53 | msgstr "" 54 | "Англоязычный чат: `Private chat " 55 | "`__" 56 | 57 | #: ../../index.rst:24 58 | msgid "" 59 | "Russian chat: `@pytelegrambotapi_talks_ru " 60 | "`__" 61 | msgstr "" 62 | "Русскоязычный чат: `@pytelegrambotapi_talks_ru " 63 | "`__" 64 | 65 | #: ../../index.rst:26 66 | msgid "News: `@pyTelegramBotAPI `__" 67 | msgstr "Новости: `@pyTelegramBotAPI `__" 68 | 69 | #: ../../index.rst:28 70 | msgid "Pypi: `Pypi `__" 71 | msgstr "" 72 | 73 | #: ../../index.rst:30 74 | msgid "" 75 | "Source: `Github repository " 76 | "`__" 77 | msgstr "" 78 | "Исходники: `Github repository " 79 | "`__" 80 | 81 | #: ../../index.rst:33 82 | msgid "Some features:" 83 | msgstr "Некоторые особенности:" 84 | 85 | #: ../../index.rst:34 86 | msgid "Easy to learn and use." 87 | msgstr "Простой в изучении и использовании." 88 | 89 | #: ../../index.rst:36 90 | msgid "Easy to understand." 91 | msgstr "Простой в понимании." 92 | 93 | #: ../../index.rst:38 94 | msgid "Both sync and async." 95 | msgstr "И синхронный, и асинхронный." 96 | 97 | #: ../../index.rst:40 98 | msgid "Examples on features." 99 | msgstr "Примеры возможностей." 100 | 101 | #: ../../index.rst:42 102 | msgid "States" 103 | msgstr "Состояния (стейты, FSM)" 104 | 105 | #: ../../index.rst:44 106 | msgid "And more..." 107 | msgstr "И другое..." 108 | 109 | #: ../../index.rst:47 110 | msgid "Content" 111 | msgstr "Содержимое" 112 | 113 | #: ../../index.rst:63 114 | msgid "Indices and tables" 115 | msgstr "Ссылки" 116 | 117 | #: ../../index.rst:65 118 | msgid ":ref:`genindex`" 119 | msgstr "" 120 | 121 | #: ../../index.rst:66 122 | msgid ":ref:`modindex`" 123 | msgstr "" 124 | 125 | #: ../../index.rst:67 126 | msgid ":ref:`search`" 127 | msgstr "" 128 | 129 | -------------------------------------------------------------------------------- /examples/custom_states.py: -------------------------------------------------------------------------------- 1 | import telebot # telebot 2 | 3 | from telebot import custom_filters 4 | from telebot.handler_backends import State, StatesGroup #States 5 | 6 | # States storage 7 | from telebot.storage import StateMemoryStorage 8 | 9 | 10 | # Starting from version 4.4.0+, we support storages. 11 | # StateRedisStorage -> Redis-based storage. 12 | # StatePickleStorage -> Pickle-based storage. 13 | # For redis, you will need to install redis. 14 | # Pass host, db, password, or anything else, 15 | # if you need to change config for redis. 16 | # Pickle requires path. Default path is in folder .state-saves. 17 | # If you were using older version of pytba for pickle, 18 | # you need to migrate from old pickle to new by using 19 | # StatePickleStorage().convert_old_to_new() 20 | 21 | 22 | 23 | # Now, you can pass storage to bot. 24 | state_storage = StateMemoryStorage() # you can init here another storage 25 | 26 | bot = telebot.TeleBot("TOKEN", 27 | state_storage=state_storage) 28 | 29 | 30 | # States group. 31 | class MyStates(StatesGroup): 32 | # Just name variables differently 33 | name = State() # creating instances of State class is enough from now 34 | surname = State() 35 | age = State() 36 | 37 | 38 | 39 | 40 | @bot.message_handler(commands=['start']) 41 | def start_ex(message): 42 | """ 43 | Start command. Here we are starting state 44 | """ 45 | bot.set_state(message.from_user.id, MyStates.name, message.chat.id) 46 | bot.send_message(message.chat.id, 'Hi, write me a name') 47 | 48 | 49 | # Any state 50 | @bot.message_handler(state="*", commands=['cancel']) 51 | def any_state(message): 52 | """ 53 | Cancel state 54 | """ 55 | bot.send_message(message.chat.id, "Your state was cancelled.") 56 | bot.delete_state(message.from_user.id, message.chat.id) 57 | 58 | @bot.message_handler(state=MyStates.name) 59 | def name_get(message): 60 | """ 61 | State 1. Will process when user's state is MyStates.name. 62 | """ 63 | bot.send_message(message.chat.id, 'Now write me a surname') 64 | bot.set_state(message.from_user.id, MyStates.surname, message.chat.id) 65 | with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 66 | data['name'] = message.text 67 | 68 | 69 | @bot.message_handler(state=MyStates.surname) 70 | def ask_age(message): 71 | """ 72 | State 2. Will process when user's state is MyStates.surname. 73 | """ 74 | bot.send_message(message.chat.id, "What is your age?") 75 | bot.set_state(message.from_user.id, MyStates.age, message.chat.id) 76 | with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 77 | data['surname'] = message.text 78 | 79 | # result 80 | @bot.message_handler(state=MyStates.age, is_digit=True) 81 | def ready_for_answer(message): 82 | """ 83 | State 3. Will process when user's state is MyStates.age. 84 | """ 85 | with bot.retrieve_data(message.from_user.id, message.chat.id) as data: 86 | msg = ("Ready, take a look:\n" 87 | f"Name: {data['name']}\n" 88 | f"Surname: {data['surname']}\n" 89 | f"Age: {message.text}") 90 | bot.send_message(message.chat.id, msg, parse_mode="html") 91 | bot.delete_state(message.from_user.id, message.chat.id) 92 | 93 | #incorrect number 94 | @bot.message_handler(state=MyStates.age, is_digit=False) 95 | def age_incorrect(message): 96 | """ 97 | Wrong response for MyStates.age 98 | """ 99 | bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number') 100 | 101 | # register filters 102 | 103 | bot.add_custom_filter(custom_filters.StateFilter(bot)) 104 | bot.add_custom_filter(custom_filters.IsDigitFilter()) 105 | 106 | bot.infinity_polling(skip_pending=True) 107 | -------------------------------------------------------------------------------- /docs/source/locales/en/LC_MESSAGES/calldata.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2022, coder2020official 3 | # This file is distributed under the same license as the pyTelegramBotAPI 4 | # Documentation package. 5 | # FIRST AUTHOR , 2022. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: pyTelegramBotAPI Documentation \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-29 14:44+0400\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.9.1\n" 20 | 21 | #: ../../calldata.rst:4 22 | msgid "Callback data factory" 23 | msgstr "" 24 | 25 | #: ../../calldata.rst:6 26 | msgid "Callback data factory in pyTelegramBotAPI" 27 | msgstr "" 28 | 29 | #: ../../calldata.rst:6 30 | msgid "" 31 | "ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, " 32 | "factory" 33 | msgstr "" 34 | 35 | #: ../../calldata.rst:12 36 | msgid "callback\\_data file" 37 | msgstr "" 38 | 39 | #: of telebot.callback_data:1 40 | msgid "Callback data factory's file." 41 | msgstr "" 42 | 43 | #: of telebot.callback_data.CallbackData:1 44 | #: telebot.callback_data.CallbackDataFilter:1 45 | msgid "Bases: :py:class:`object`" 46 | msgstr "" 47 | 48 | #: of telebot.callback_data.CallbackData:1 49 | msgid "Callback data factory This class will help you to work with CallbackQuery" 50 | msgstr "" 51 | 52 | #: of telebot.callback_data.CallbackData.filter:1 53 | msgid "Generate filter" 54 | msgstr "" 55 | 56 | #: of telebot.callback_data.CallbackData.filter 57 | #: telebot.callback_data.CallbackData.new 58 | #: telebot.callback_data.CallbackData.parse 59 | #: telebot.callback_data.CallbackDataFilter.check 60 | msgid "Parameters" 61 | msgstr "" 62 | 63 | #: of telebot.callback_data.CallbackData.filter:3 64 | msgid "specified named parameters will be checked with CallbackQuery.data" 65 | msgstr "" 66 | 67 | #: of telebot.callback_data.CallbackData.filter 68 | #: telebot.callback_data.CallbackData.new 69 | #: telebot.callback_data.CallbackData.parse 70 | #: telebot.callback_data.CallbackDataFilter.check 71 | msgid "Returns" 72 | msgstr "" 73 | 74 | #: of telebot.callback_data.CallbackData.filter:4 75 | msgid "CallbackDataFilter class" 76 | msgstr "" 77 | 78 | #: of telebot.callback_data.CallbackData.new:1 79 | msgid "Generate callback data" 80 | msgstr "" 81 | 82 | #: of telebot.callback_data.CallbackData.new:3 83 | msgid "positional parameters of CallbackData instance parts" 84 | msgstr "" 85 | 86 | #: of telebot.callback_data.CallbackData.new:4 87 | msgid "named parameters" 88 | msgstr "" 89 | 90 | #: of telebot.callback_data.CallbackData.new:5 91 | msgid "str" 92 | msgstr "" 93 | 94 | #: of telebot.callback_data.CallbackData.parse:1 95 | msgid "Parse data from the callback data" 96 | msgstr "" 97 | 98 | #: of telebot.callback_data.CallbackData.parse:3 99 | msgid "" 100 | "string, use to telebot.types.CallbackQuery to parse it from string to a " 101 | "dict" 102 | msgstr "" 103 | 104 | #: of telebot.callback_data.CallbackData.parse:4 105 | msgid "dict parsed from callback data" 106 | msgstr "" 107 | 108 | #: of telebot.callback_data.CallbackDataFilter:1 109 | msgid "Filter for CallbackData." 110 | msgstr "" 111 | 112 | #: of telebot.callback_data.CallbackDataFilter.check:1 113 | msgid "Checks if query.data appropriates to specified config" 114 | msgstr "" 115 | 116 | #: of telebot.callback_data.CallbackDataFilter.check:3 117 | msgid "telebot.types.CallbackQuery" 118 | msgstr "" 119 | 120 | #: of telebot.callback_data.CallbackDataFilter.check:6 121 | msgid "True if query.data appropriates to specified config" 122 | msgstr "" 123 | 124 | #: of telebot.callback_data.CallbackDataFilter.check 125 | msgid "Return type" 126 | msgstr "" 127 | 128 | -------------------------------------------------------------------------------- /telebot/ext/sync/webhooks.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is used by TeleBot.run_webhooks() function. 3 | Fastapi is required to run this script. 4 | """ 5 | 6 | # modules required for running this script 7 | fastapi_installed = True 8 | 9 | try: 10 | import fastapi 11 | from fastapi.responses import JSONResponse 12 | from fastapi.requests import Request 13 | import uvicorn 14 | except ImportError: 15 | fastapi_installed = False 16 | 17 | from telebot.types import Update 18 | 19 | from typing import Optional 20 | 21 | 22 | class SyncWebhookListener: 23 | def __init__(self, bot, 24 | secret_token: str, 25 | host: Optional[str]="127.0.0.1", 26 | port: Optional[int]=443, 27 | ssl_context: Optional[tuple]=None, 28 | url_path: Optional[str]=None, 29 | ) -> None: 30 | """ 31 | Synchronous implementation of webhook listener 32 | for synchronous version of telebot. 33 | Not supposed to be used manually by user. 34 | Use TeleBot.run_webhooks() instead. 35 | 36 | :param bot: TeleBot instance. 37 | :type bot: telebot.TeleBot 38 | 39 | :param secret_token: Telegram secret token 40 | :type secret_token: str 41 | 42 | :param host: Webhook host 43 | :type host: str 44 | 45 | :param port: Webhook port 46 | :type port: int 47 | 48 | :param ssl_context: SSL context 49 | :type ssl_context: tuple 50 | 51 | :param url_path: Webhook url path 52 | :type url_path: str 53 | 54 | :raises ImportError: If FastAPI or uvicorn is not installed. 55 | :raises ImportError: If Starlette version is too old. 56 | 57 | :return: None 58 | """ 59 | self._check_dependencies() 60 | 61 | self.app = fastapi.FastAPI() 62 | self._secret_token = secret_token 63 | self._bot = bot 64 | self._port = port 65 | self._host = host 66 | self._ssl_context = ssl_context 67 | self._url_path = url_path 68 | self._prepare_endpoint_urls() 69 | 70 | 71 | @staticmethod 72 | def _check_dependencies(): 73 | if not fastapi_installed: 74 | raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.') 75 | 76 | import starlette 77 | if starlette.__version__ < '0.20.2': 78 | raise ImportError('Starlette version is too old. Please upgrade it: `pip3 install starlette -U`') 79 | return 80 | 81 | 82 | def _prepare_endpoint_urls(self): 83 | self.app.add_api_route(endpoint=self.process_update,path= self._url_path, methods=["POST"]) 84 | 85 | 86 | def process_update(self, request: Request, update: dict): 87 | """ 88 | Processes updates. 89 | 90 | :meta private: 91 | """ 92 | # header containsX-Telegram-Bot-Api-Secret-Token 93 | if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token: 94 | # secret token didn't match 95 | return JSONResponse(status_code=403, content={"error": "Forbidden"}) 96 | if request.headers.get('content-type') == 'application/json': 97 | self._bot.process_new_updates([Update.de_json(update)]) 98 | return JSONResponse('', status_code=200) 99 | 100 | return JSONResponse(status_code=403, content={"error": "Forbidden"}) 101 | 102 | 103 | def run_app(self): 104 | """ 105 | Run app with the given parameters to init. 106 | Not supposed to be used manually by user. 107 | 108 | :return: None 109 | """ 110 | 111 | uvicorn.run(app=self.app, 112 | host=self._host, 113 | port=self._port, 114 | ssl_certfile=self._ssl_context[0], 115 | ssl_keyfile=self._ssl_context[1] 116 | ) 117 | --------------------------------------------------------------------------------