I'm programming a telegram bot in python that, on command, starts sending a photo of a window on my computer to the chat every few seconds. Of course I don't want the chat to get spammed with photos so instead I want to go back and edit the first message that I send using edit_media
.
Currently my callback function to the command looks like this:
def callback(update: Update, context: CallbackContext):
first = True
while True:
image = screenshot('Snake') # Gets a screenshot of the window
bytesio = io.BytesIO()
image.save(bytesio, format='PNG')
bytes_image = bytes(bytesio.getvalue()) # Convert to bytes object
if first: # First time send a full message
context.bot.send_photo(update.message.chat_id, bytes_image)
first = False
else:
update.message.edit_media(media=InputMediaPhoto(media=bytes_image)) # Edit the message with the next photo
time.sleep(2)
When this function runs, the first message is sent successfully, but trying to edit the message raises an error:
telegram.error.BadRequest: Message can't be edited
How do I solve this so that the image is successfully edited?
The full traceback of the error is:
Traceback (most recent call last):
File "C:\Users\...\telegram\ext\dispatcher.py", line 555, in process_update
handler.handle_update(update, self, check, context)
File "C:\Users\...\telegram\ext\handler.py", line 198, in handle_update
return self.callback(update, context)
File "C:\Users\...\TelegramGameHub\main.py", line 56, in snake
update.message.edit_media(media=InputMediaPhoto(media=bytes_image))
File "C:\Users\...\telegram\message.py", line 2016, in edit_media
return self.bot.edit_message_media(
File "C:\Users\...\telegram\bot.py", line 130, in decorator
result = func(*args, **kwargs)
File "C:\Users\...\telegram\bot.py", line 2723, in edit_message_media
return self._message(
File "C:\Users\...\telegram\ext\extbot.py", line 199, in _message
result = super()._message(
File "C:\Users\...\telegram\bot.py", line 332, in _message
result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs)
File "C:\Users\...\telegram\bot.py", line 295, in _post
return self.request.post(
File "C:\Users\...\telegram\utils\request.py", line 354, in post
result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs)
File "C:\Users\...\telegram\utils\request.py", line 279, in _request_wrapper
raise BadRequest(message)
The problem is that your line
update.message.edit_media(media=InputMediaPhoto(media=bytes_image))
doesn't edit the photo message that you sent. It instead tries to edit the message that initially triggered the callback.
To get a hold of the message that you send, you'll need to do something like
message = context.bot.send_photo(update.message.chat_id, bytes_image)
Note that PTB provides shortcuts for these kind of things. So you could abbreviate this to
message = update.message.reply_photo(bytes_image)
which is (almost) equivalent.
Now you can call message.edit_media(...)
to update the photo.
Another thing to note is that your loop
while True:
...
time.sleep(2)
is blocking. That means that after entering the function callback
, your bot won't process any other updates. (Side note in case you know what run_async
does: Even if you run this callback asynchronously, it will block one of the worker threads and as soon as enough updates have triggered this callback, all the worker threads are blocked and your bot won't process any more updates)
I highly recommend to use the built in JobQueue
for such things. See also the wiki page and the example.
Disclaimer: I'm currently the maintainer of python-telegram-bot
.