4

Im writing a telegram bot using the python telepot api. I'm now stuck at the point where I want to send a picture which directly comes from an URL without storing it locally. Telepot provides the following instruction to send a photo:

>>> f = open('zzzzzzzz.jpg', 'rb')  # some file on local disk
>>> response = bot.sendPhoto(chat_id, f)

Now im using

f = urllib2.urlopen('http://i.imgur.com/B1fzGoh.jpg')
bot.sendPhoto(chat_id, f)

The problem here is that urllib2.urlopen('url') provide me file-like object like:

<addinfourl at 140379102313792 whose fp = <socket._fileobject object at 0x7fac8e86d750>>

and not like open('myFile.jpg', 'rb') a file object like:

<open file 'app-root/runtime/repo/myImage.jpg', mode 'rb' at 0x7fac8f322540>

If I send the file-like object in sendPhoto() I get the following error: Traceback (most recent call last):

[Wed Feb 10 06:21:09 2016] [error]   File "/var/lib/openshift/56b8e2787628e1484a00013e/python/virtenv/lib/python2.7/site-packages/telepot/__init__.py", line 340, in handle
[Wed Feb 10 06:21:09 2016] [error]     callback(update['message'])
[Wed Feb 10 06:21:09 2016] [error]   File "/var/lib/openshift/56b8e2787628e1484a00013e/app-root/runtime/repo/moviequiz_main.py", line 35, in handle
[Wed Feb 10 06:21:09 2016] [error]     response = bot.sendPhoto(chat_id, gif)
[Wed Feb 10 06:21:09 2016] [error]   File "/var/lib/openshift/56b8e2787628e1484a00013e/python/virtenv/lib/python2.7/site-packages/telepot/__init__.py", line 230, in sendPhoto
[Wed Feb 10 06:21:09 2016] [error]     return self._sendFile(photo, 'photo', p)
[Wed Feb 10 06:21:09 2016] [error]   File "/var/lib/openshift/56b8e2787628e1484a00013e/python/virtenv/lib/python2.7/site-packages/telepot/__init__.py", line 226, in _sendFile
[Wed Feb 10 06:21:09 2016] [error]     return self._parse(r)
[Wed Feb 10 06:21:09 2016] [error]   File "/var/lib/openshift/56b8e2787628e1484a00013e/python/virtenv/lib/python2.7/site-packages/telepot/__init__.py", line 172, in _parse
[Wed Feb 10 06:21:09 2016] [error]     raise BadHTTPResponse(response.status_code, response.text)
[Wed Feb 10 06:21:09 2016] [error] BadHTTPResponse: (414, u'<html>\\r\\n<head><title>414 Request-URI Too Large</title></head>\\r\\n<body bgcolor="white">\\r\\n<center><h1>414 Request-URI Too Large</h1></center>\\r\\n<hr><center>nginx/1.9.1</center>\\r\\n</body>\\r\\n</html>\\r\\n')

There is a solution for a different telegram-bot project provided here where they send the urllib2.urlopen('url').read() back to telegram but in my case this generates the same error as without .read() .

How could I get the file from the url as file object (best would be without saving it locally)? Or how do I get the "file object" out of the "file-like object" provided by urlopen()?

Thanks for any help :)

Community
  • 1
  • 1
basilius
  • 57
  • 1
  • 4
  • Telepot's `sendPhoto()` method interprets the second argument this way: if it is a file, the content is uploaded using multipart/form-data; otherwise, it is given to the Bot API as a string, indicating an existing `file_id` on the servers. Your problem arises because, obviously, a file-like object is *not* a file, therefore *incorrectly* treated as the latter case. Your desire to use `sendPhoto()` without saving to a local file is perfectly reasonable and legitimate. If it is important enough to you, please go to telepot's Github homepage and open an issue. – Nick Lee Feb 10 '16 at 15:12
  • As the author of telepot, I think telepot *should* treat your case properly. I will try to fix your issue in a future release. – Nick Lee Feb 10 '16 at 15:13
  • Okay now I understand whats going on! I didn't know that it simply treats it as `file_id`. In this case the HttpResponse makes sense to me. Thanks for your help and for the awesome telepot api! Do you still want me to open an specific issue on telepot's github? – basilius Feb 10 '16 at 15:28
  • @NickLee I made a quick and plain fix for my case: I changed the `else` in function `_isfile` from `return type(f) is file` to `return type(f) is file or hasattr(f, 'read')` -> [line 201 __init__.py](https://github.com/nickoala/telepot/blob/411d8efc4e952a9440a442d145115e4a91830a29/telepot/__init__.py#L201) And then the file retrieved from `f = urllib2.urlopen('url')` needs a name `f.name = "name.jpg"` because it needs to provide a file extension. – basilius Feb 10 '16 at 21:48
  • Thank you, that would work. In order to make it into a future release, I have to do the same for Python 3. And I am thinking of a way to handle the file extension more seamlessly, if that is possible. Someone brought up the file extension issue some time ago .... – Nick Lee Feb 11 '16 at 04:43
  • 1
    Telepot has been updated. @basilius, It now supports your use case. Please read the `sendPhoto()` method in the [reference](https://github.com/nickoala/telepot/blob/master/REFERENCE.md) – Nick Lee Feb 21 '16 at 10:30
  • Thanks for the update! I updated to 6.5 today and it works perfectly – basilius Feb 25 '16 at 13:16
  • @NickLee your link is broken, correct link: https://core.telegram.org/bots/api#sendphoto – pocjoc May 13 '17 at 15:13

2 Answers2

3

In current Bot Api 2.3.1, You can simply send url of file to the server:

bot.sendPhoto(chat_id, "http://i.imgur.com/B1fzGoh.jpg");

That's it.

You don't even need to download it, Telegram would upload it by itself.

2i3r
  • 423
  • 1
  • 3
  • 13
2

Yes.

You can make it async (or not):

async with aiohttp.get("http://i.imgur.com/B1fzGoh.jpg") as r:
    result = r.read()
await self.sendPhoto(chat_id, ('image.jpg', result))