1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Merge branch 'master' into patch-2

This commit is contained in:
Natanael Andrés Garrido 2019-09-23 10:25:18 -03:00 committed by GitHub
commit f8e7c0f819
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 23 deletions

View File

@ -26,6 +26,7 @@
* [Using web hooks](#using-web-hooks) * [Using web hooks](#using-web-hooks)
* [Logging](#logging) * [Logging](#logging)
* [Proxy](#proxy) * [Proxy](#proxy)
* [New in library](#new-in-library)
* [F.A.Q.](#faq) * [F.A.Q.](#faq)
* [Bot 2.0](#bot-20) * [Bot 2.0](#bot-20)
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat) * [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
@ -510,6 +511,10 @@ apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'}
``` ```
## New in library
06.06.2019 - Добавленна поддержка опросов (Poll). Добавлены функции send_poll, stop_poll
## F.A.Q. ## F.A.Q.
### Bot 2.0 ### Bot 2.0
@ -524,16 +529,16 @@ Telegram Bot API support new type Chat for message.chat.
- Check the ```type``` attribute in ```Chat``` object: - Check the ```type``` attribute in ```Chat``` object:
- -
```python ```python
if message.chat.type == “private”: if message.chat.type == "private":
# private chat message # private chat message
if message.chat.type == “group”: if message.chat.type == "group":
# group chat message # group chat message
if message.chat.type == “supergroup”: if message.chat.type == "supergroup":
# supergroup chat message # supergroup chat message
if message.chat.type == “channel”: if message.chat.type == "channel":
# channel message # channel message
``` ```
@ -576,7 +581,6 @@ Get help. Discuss. Chat.
* [EmaProject](https://github.com/halkliff/emaproject) by [*halkliff*](https://github.com/halkliff) - Ema - Eastern Media Assistant was made thinking on the ease-to-use feature. Coding here is simple, as much as is fast and powerful. * [EmaProject](https://github.com/halkliff/emaproject) by [*halkliff*](https://github.com/halkliff) - Ema - Eastern Media Assistant was made thinking on the ease-to-use feature. Coding here is simple, as much as is fast and powerful.
* [filmratingbot](http://t.me/filmratingbot)([source](https://github.com/jcolladosp/film-rating-bot)) by [*jcolladosp*](https://github.com/jcolladosp) - Telegram bot using the Python API that gets films rating from IMDb and metacritic * [filmratingbot](http://t.me/filmratingbot)([source](https://github.com/jcolladosp/film-rating-bot)) by [*jcolladosp*](https://github.com/jcolladosp) - Telegram bot using the Python API that gets films rating from IMDb and metacritic
* [you2mp3bot](http://t.me/you2mp3bot)([link](https://storebot.me/bot/you2mp3bot)) - This bot can convert a Youtube video to Mp3. All you need is send the URL video. * [you2mp3bot](http://t.me/you2mp3bot)([link](https://storebot.me/bot/you2mp3bot)) - This bot can convert a Youtube video to Mp3. All you need is send the URL video.
* [areajugonesbot](http://t.me/areajugonesbot)([link](http://t.me/areajugonesbot)) - The areajugonesbot sends news published on the videogames blog Areajugones to Telegram.
* [Send2Kindlebot](http://t.me/Send2KindleBot) ([source](https://github.com/GabrielRF/Send2KindleBot)) by *GabrielRF* - Send to Kindle service. * [Send2Kindlebot](http://t.me/Send2KindleBot) ([source](https://github.com/GabrielRF/Send2KindleBot)) by *GabrielRF* - Send to Kindle service.
* [RastreioBot](http://t.me/RastreioBot) ([source](https://github.com/GabrielRF/RastreioBot)) by *GabrielRF* - Bot used to track packages on the Brazilian Mail Service. * [RastreioBot](http://t.me/RastreioBot) ([source](https://github.com/GabrielRF/RastreioBot)) by *GabrielRF* - Bot used to track packages on the Brazilian Mail Service.
* [filex_bot](http://t.me/filex_bot)([link](https://github.com/victor141516/FileXbot-telegram)) * [filex_bot](http://t.me/filex_bot)([link](https://github.com/victor141516/FileXbot-telegram))
@ -588,6 +592,12 @@ Get help. Discuss. Chat.
* [Bot-Telegram-Shodan ](https://github.com/rubenleon/Bot-Telegram-Shodan) by [rubenleon](https://github.com/rubenleon) * [Bot-Telegram-Shodan ](https://github.com/rubenleon/Bot-Telegram-Shodan) by [rubenleon](https://github.com/rubenleon)
* [MandangoBot](https://t.me/MandangoBot) by @Alvaricias - Bot for managing Marvel Strike Force alliances (only in spanish, atm). * [MandangoBot](https://t.me/MandangoBot) by @Alvaricias - Bot for managing Marvel Strike Force alliances (only in spanish, atm).
* [ManjaroBot](https://t.me/ManjaroBot) by [@NeoRanger](https://github.com/neoranger) - Bot for Manjaro Linux Spanish group with a lot of info for Manjaro Newbies. * [ManjaroBot](https://t.me/ManjaroBot) by [@NeoRanger](https://github.com/neoranger) - Bot for Manjaro Linux Spanish group with a lot of info for Manjaro Newbies.
* [VigoBusTelegramBot](https://t.me/vigobusbot) ([GitHub](https://github.com/Pythoneiro/VigoBus-TelegramBot)) - Bot that provides buses coming to a certain stop and their remaining time for the city of Vigo (Galicia - Spain)
* [kaishnik-bot](https://t.me/kaishnik_bot) ([source](https://github.com/airatk/kaishnik-bot)) by *airatk* - bot which shows all the necessary information to KNTRU-KAI students.
* [Creation Date](https://t.me/creationdatebot) by @karipov - interpolates account creation dates based on telegram given IDs
* [m0xbot](https://t.me/m0xbot) by [kor0p](https://github.com/kor0p) - tic-tac-toe.
* [kboardbot](https://t.me/kboardbot) by [kor0p](https://github.com/kor0p) - inline switches keyboard layout (English, Hebrew, Ukrainian, Russian).
* [Robbie](https://t.me/romdeliverybot) ([source](https://github.com/FacuM/romdeliverybot_support)) by @FacuM - Support Telegram bot for developers and maintainers.
* [AsadovBot](https://t.me/asadov_bot) ([source])(https://github.com/desexcile/BotApi)) by @DesExcile - Сatalog of poems by Eduard Asadov.
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh. Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.

View File

@ -9,8 +9,8 @@ bot = telebot.TeleBot(TELEGRAM_TOKEN)
def gen_markup(): def gen_markup():
markup = InlineKeyboardMarkup() markup = InlineKeyboardMarkup()
markup.row_width = 2 markup.row_width = 2
markup.add(InlineKeyboardButton("Yes", callback_data=f"cb_yes"), markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
InlineKeyboardButton("No", callback_data=f"cb_no")) InlineKeyboardButton("No", callback_data="cb_no"))
return markup return markup
@bot.callback_query_handler(func=lambda call: True) @bot.callback_query_handler(func=lambda call: True)

View File

@ -86,11 +86,13 @@ def echo_message(message):
# Remove webhook, it fails sometimes the set if there is a previous webhook # Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook() #bot.remove_webhook()
# Set webhook # Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, # Beacuse telegram bot api server will check webhook server is alive.
certificate=open(WEBHOOK_SSL_CERT, 'r')) # Here we need set webhook after server started manually.
#bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
# certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Start server # Start server
httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT), httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),

View File

@ -113,6 +113,7 @@ class TeleBot:
getUserProfilePhotos getUserProfilePhotos
getUpdates getUpdates
getFile getFile
sendPoll
kickChatMember kickChatMember
unbanChatMember unbanChatMember
restrictChatMember restrictChatMember
@ -364,12 +365,12 @@ class TeleBot:
for listener in self.update_listener: for listener in self.update_listener:
self._exec_task(listener, new_messages) self._exec_task(listener, new_messages)
def infinity_polling(self, *args, **kwargs): def infinity_polling(self, timeout=20, *args, **kwargs):
while not self.__stop_polling.is_set(): while not self.__stop_polling.is_set():
try: try:
self.polling(*args, **kwargs) self.polling(timeout=timeout, *args, **kwargs)
except Exception as e: except Exception as e:
time.sleep(5) time.sleep(timeout)
pass pass
logger.info("Break infinity polling") logger.info("Break infinity polling")
@ -1044,6 +1045,12 @@ class TeleBot:
disable_notification, reply_to_message_id, reply_markup, provider_data) disable_notification, reply_to_message_id, reply_markup, provider_data)
return types.Message.de_json(result) return types.Message.de_json(result)
def send_poll(self, chat_id, poll, disable_notifications=False, reply_to_message=None, reply_markup=None):
return types.Message.de_json(apihelper.send_poll(self.token, chat_id, poll.question, poll.options, disable_notifications, reply_to_message, reply_markup))
def stop_poll(self, chat_id, message_id):
return types.Poll.de_json(apihelper.stop_poll(self.token, chat_id, message_id))
def answer_shipping_query(self, shipping_query_id, ok, shipping_options=None, error_message=None): def answer_shipping_query(self, shipping_query_id, ok, shipping_options=None, error_message=None):
return apihelper.answer_shipping_query(self.token, shipping_query_id, ok, shipping_options, error_message) return apihelper.answer_shipping_query(self.token, shipping_query_id, ok, shipping_options, error_message)
@ -1333,7 +1340,7 @@ class TeleBot:
bot.send_message(message.chat.id, 'Document received, sir!') bot.send_message(message.chat.id, 'Document received, sir!')
# Handle all other commands. # Handle all other commands.
@bot.message_handler(func=lambda message: True, content_types=['audio', 'video', 'document', 'text', 'location', 'contact', 'sticker']) @bot.message_handler(func=lambda message: True, content_types=['audio', 'photo', 'voice', 'video', 'document', 'text', 'location', 'contact', 'sticker'])
def default_command(message): def default_command(message):
bot.send_message(message.chat.id, "This is the default command handler.") bot.send_message(message.chat.id, "This is the default command handler.")
@ -1750,3 +1757,11 @@ class AsyncTeleBot(TeleBot):
@util.async_dec() @util.async_dec()
def delete_sticker_from_set(self, *args, **kwargs): def delete_sticker_from_set(self, *args, **kwargs):
return TeleBot.delete_sticker_from_set(self, *args, **kwargs) return TeleBot.delete_sticker_from_set(self, *args, **kwargs)
@util.async_dec()
def send_poll(self, *args, **kwargs):
return TeleBot.send_poll(self, *args, **kwargs)
@util.async_dec()
def stop_poll(self, *args, **kwargs):
return TeleBot.stop_poll(self, *args, **kwargs)

View File

@ -619,7 +619,7 @@ def edit_message_text(token, text, chat_id=None, message_id=None, inline_message
payload['disable_web_page_preview'] = disable_web_page_preview payload['disable_web_page_preview'] = disable_web_page_preview
if reply_markup: if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup) payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload) return _make_request(token, method_url, params=payload, method='post')
def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None,
@ -636,7 +636,7 @@ def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_m
payload['parse_mode'] = parse_mode payload['parse_mode'] = parse_mode
if reply_markup: if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup) payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload) return _make_request(token, method_url, params=payload, method='post')
def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None): def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
@ -665,13 +665,13 @@ def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_messa
payload['inline_message_id'] = inline_message_id payload['inline_message_id'] = inline_message_id
if reply_markup: if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup) payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload) return _make_request(token, method_url, params=payload, method='post')
def delete_message(token, chat_id, message_id): def delete_message(token, chat_id, message_id):
method_url = r'deleteMessage' method_url = r'deleteMessage'
payload = {'chat_id': chat_id, 'message_id': message_id} payload = {'chat_id': chat_id, 'message_id': message_id}
return _make_request(token, method_url, params=payload) return _make_request(token, method_url, params=payload, method='post')
# Game # Game
@ -938,6 +938,26 @@ def delete_sticker_from_set(token, sticker):
return _make_request(token, method_url, params=payload, method='post') return _make_request(token, method_url, params=payload, method='post')
def send_poll(token, chat_id, question, options, disable_notifications=False, reply_to_message_id=None, reply_markup=None):
method_url = r'sendPoll'
payload = {'chat_id': str(chat_id), 'question': question, 'options': _convert_list_json_serializable(options)}
if disable_notifications:
payload['disable_notification'] = disable_notifications
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def stop_poll(token, chat_id, message_id, reply_markup=None):
method_url = r'stopPoll'
payload = {'chat_id': str(chat_id), 'message_id': message_id}
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def _convert_list_json_serializable(results): def _convert_list_json_serializable(results):
ret = '' ret = ''
for r in results: for r in results:

View File

@ -368,6 +368,9 @@ class Message(JsonDeserializable):
if 'connected_website' in obj: if 'connected_website' in obj:
opts['connected_website'] = obj['connected_website'] opts['connected_website'] = obj['connected_website']
content_type = 'connected_website' content_type = 'connected_website'
if 'poll' in obj:
opts['poll'] = Poll.de_json(obj['poll'])
content_type = 'poll'
return cls(message_id, from_user, date, chat, content_type, opts, json_string) return cls(message_id, from_user, date, chat, content_type, opts, json_string)
@classmethod @classmethod
@ -885,9 +888,30 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
return json_dict return json_dict
class LoginUrl(JsonSerializable):
def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None):
self.url = url
self.forward_text = forward_text
self.bot_username = bot_username
self.request_write_access = request_write_access
def to_json(self):
return json.dumps(self.to_dic())
def to_dic(self):
json_dic = {'url': self.url}
if self.forward_text:
json_dic['forward_text'] = self.forward_text
if self.bot_username:
json_dic['bot_username'] = self.bot_username
if self.request_write_access:
json_dic['request_write_access'] = self.request_write_access
return json_dic
class InlineKeyboardButton(JsonSerializable): class InlineKeyboardButton(JsonSerializable):
def __init__(self, text, url=None, callback_data=None, switch_inline_query=None, def __init__(self, text, url=None, callback_data=None, switch_inline_query=None,
switch_inline_query_current_chat=None, callback_game=None, pay=None): switch_inline_query_current_chat=None, callback_game=None, pay=None, login_url=None):
self.text = text self.text = text
self.url = url self.url = url
self.callback_data = callback_data self.callback_data = callback_data
@ -895,6 +919,7 @@ class InlineKeyboardButton(JsonSerializable):
self.switch_inline_query_current_chat = switch_inline_query_current_chat self.switch_inline_query_current_chat = switch_inline_query_current_chat
self.callback_game = callback_game self.callback_game = callback_game
self.pay = pay self.pay = pay
self.login_url = login_url
def to_json(self): def to_json(self):
return json.dumps(self.to_dic()) return json.dumps(self.to_dic())
@ -913,6 +938,8 @@ class InlineKeyboardButton(JsonSerializable):
json_dic['callback_game'] = self.callback_game json_dic['callback_game'] = self.callback_game
if self.pay is not None: if self.pay is not None:
json_dic['pay'] = self.pay json_dic['pay'] = self.pay
if self.login_url is not None:
json_dic['login_url'] = self.login_url.to_dic()
return json_dic return json_dic
@ -2173,3 +2200,48 @@ class InputMediaDocument(InputMedia):
if self.thumb: if self.thumb:
ret['thumb'] = self.thumb ret['thumb'] = self.thumb
return ret return ret
class PollOption(JsonSerializable, JsonDeserializable):
@classmethod
def de_json(cls, json_type):
obj = cls.check_json(json_type)
text = obj['text']
voter_count = int(obj['voter_count'])
option = cls(text)
option.voter_count = voter_count
return option
def __init__(self, text):
self.text = text
self.voter_count = 0
def to_json(self):
return json.dumps(self.text)
class Poll(JsonDeserializable):
@classmethod
def de_json(cls, json_type):
obj = cls.check_json(json_type)
poll_id = obj['id']
question = obj['question']
poll = cls(question)
options = []
for opt in obj['options']:
options.append(PollOption.de_json(opt))
poll.options = options
is_closed = obj['is_closed']
poll.id = poll_id
poll.is_closed = is_closed
return poll
def __init__(self, question):
self.options = []
self.question = question
def add(self, option):
if type(option) is PollOption:
self.options.append(option)
else:
self.options.append(PollOption(option))