eternnoir / pyTelegramBotAPI

Python Telegram bot api.
GNU General Public License v2.0
8.11k stars 2.03k forks source link

Where should I put apihelper.API_URL and when do I need to bot.log_out() #2243

Closed iti-D closed 6 months ago

iti-D commented 6 months ago

Please answer these questions before submitting your issue. Thanks!

  1. What version of pyTelegramBotAPI are you using? pytelegrambotapi 4.17.0

  2. What OS are you using? Linux 20.04.1-Ubuntu x86_64 GNU/Linux

  3. What version of python are you using? Python 3.8.10

now for my question, I've deployed a local API server, so I don't have limits of files up to 20mb. I've used this docker image and ran it https://hub.docker.com/r/aiogram/telegram-bot-api

But in my code for the bot, I'm not quite sure how to use the api helper, as decribed here https://github.com/eternnoir/pyTelegramBotAPI?tab=readme-ov-file#using-local-bot-api-sever

I have two more lines I need to add to my code, right? first is apihelper.API_URL = "http://localhost:4200/bot{0}/{1}" and second one is to log out bot.log_out()

but in what order and what comes first?

Here's the structure of my code right now:

API_TOKEN = "abc"
bot = telebot.TeleBot(API_TOKEN, parse_mode=None)

# Defining message hendlers here
@bot.message_handler(...etc etc
#I have some message handlers and then:
if __name__ == "__main__":
    bot.infinity_polling()

Now, I'm not sure where to put the two lines I mentioned. I tried putting them in all combinations I could think of, after the infinity_polling, before the bot = telebot.Telebot.. really, everywhere. And the documentation isn't very descriptive.

I keep getting the error: telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 400. Description: Logged out

Also, for the URL, what are the {0} and {1} for? apihelper.API_URL = "http://localhost:4200/bot{0}/{1}" should I replace them with something? leave it be? maybe delete them since I didn't specify any path when deploying the docker?

I should note that my code isn't running. Like, I make changed and run the python code all again. Do I still need to do the log_out() function?

would really love some clarification about this.

thanks!

EDIT: More information that can be helpful: to download files I'm using the bot.get_file_url(file_id) function, and in the error it looks I'm getting a link to telegram API to try and download this file. Could it be that the get_file_url is automatically building a url for telegram API while ignoring the apihelper new URL for the API?

here are the lines in the error that caught my attention:

File "/home/ubuntu/tg_bot/download_music.py", line 61, in audio_download
    song_url = bot_main.bot.get_file_url(file_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1387, in get_file_url
    return apihelper.get_file_url(self.token, file_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 221, in get_file_url
    return "https://api.telegram.org/file/bot{0}/{1}".format(token, get_file(token, file_id)['file_path'])

here's the full error (I didn't read it all, if you see anything that can be personally identifying information in the error please tell me):

2024-04-26 01:23:10,568 (__init__.py:1212 MainThread) ERROR - TeleBot: "Threaded polling exception: A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request: file is too big"
2024-04-26 01:23:10,569 (__init__.py:1214 MainThread) ERROR - TeleBot: "Exception traceback:
Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1206, in __threaded_polling
    self.worker_pool.raise_exceptions()
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/util.py", line 150, in raise_exceptions
    raise self.exception_info
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/util.py", line 93, in run
    task(*args, **kwargs)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 8404, in _run_middlewares_and_handler
    result = handler['function'](message)
  File "bot_main.py", line 38, in download_all_now
    download_music.main()
  File "/home/ubuntu/tg_bot/download_music.py", line 82, in main
    available_functions[option](LINKS_FILE_PATH[option])
  File "/home/ubuntu/tg_bot/download_music.py", line 61, in audio_download
    song_url = bot_main.bot.get_file_url(file_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1387, in get_file_url
    return apihelper.get_file_url(self.token, file_id)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 221, in get_file_url
    return "https://api.telegram.org/file/bot{0}/{1}".format(token, get_file(token, file_id)['file_path'])
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 216, in get_file
    return _make_request(token, method_url, params={'file_id': file_id})
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 167, in _make_request
    json_result = _check_result(method_name, result)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 194, in _check_result
    raise ApiTelegramException(method_name, result, result_json)
telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request: file is too big
"
^C2024-04-26 01:27:41,275 (__init__.py:1092 MainThread) ERROR - TeleBot: "Infinity polling: polling exited"
2024-04-26 01:27:41,275 (__init__.py:1094 MainThread) ERROR - TeleBot: "Break infinity polling"

EDIT 2: now I see that a get_file_url method isn't shown in Telegram's official API https://core.telegram.org/bots/api#getfile and there's only getfile. from which you can craft the URL yourself and use it. So it seems like get_file_url has a bug? I'll now try to change my code to use get_file instead and craft the url myself, and see if it fixes the problem.

coder2020official commented 6 months ago

Afaik you logout first, then set the URL to custom bot API, then you launch the infinity polling

iti-D commented 6 months ago

Afaik you logout first, then set the URL to custom bot API, then you launch the infinity polling

getting this error right when starting the bot (without trying to download any files) telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 400. Description: Logged out

I set it up as you said:

bot = telebot.TeleBot(API_TOKEN, parse_mode=None)
bot.log_out()
apihelper.API_URL = "http://localhost:8081/bot{0}/{1}"
if __name__ == "__main__":
    bot.infinity_polling()

full error:

2024-04-26 01:54:56,370 (__init__.py:1086 MainThread) ERROR - TeleBot: "Infinity polling exception: A request to the Telegram API was unsuccessful. Error code: 400. Description: Logged out"
2024-04-26 01:54:56,372 (__init__.py:1088 MainThread) ERROR - TeleBot: "Exception traceback:
Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1081, in infinity_polling
    self.polling(non_stop=True, timeout=timeout, long_polling_timeout=long_polling_timeout,
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1166, in polling
    logger.info('Starting your bot with username: [@%s]', self.user.username)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 293, in user
    self._user = self.get_me()
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/__init__.py", line 1353, in get_me
    apihelper.get_me(self.token)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 201, in get_me
    return _make_request(token, method_url)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 167, in _make_request
    json_result = _check_result(method_name, result)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/telebot/apihelper.py", line 194, in _check_result
    raise ApiTelegramException(method_name, result, result_json)
telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 400. Description: Logged out
"
coder2020official commented 6 months ago

Did you launch the bot API server with --local parameter?

iti-D commented 6 months ago

Did you launch the bot API server with --local parameter?

No, thanks for asking. I added -e TELEGRAM_LOCAL=true to my docker run command, but I still get the same error of Error code: 400. Description: Logged out

are you sure this is the right order? I get it immediately when running the python file.

for refrence, here's the docker run command: docker run -d -p 8081:8081 --name=telegram-bot-api4 --restart=always -v telegram-bot-api-data:/var/lib/telegram-bot-api -e TELEGRAM_API_ID=<id> -e TELEGRAM_API_HASH=<hash> -e TELEGRAM_LOCAL=true aiogram/telegram-bot-api:latest

coder2020official commented 6 months ago

I think this should work. Hopefully you are not logging out very often? You just need to do it once, then bot API doesn't allow you to use itself for 10 minutes Try logging out, and remove that line, then just launch infinity polling with your API

iti-D commented 6 months ago

I think this should work. Hopefully you are not logging out very often? You just need to do it once, then bot API doesn't allow you to use itself for 10 minutes Try logging out, and remove that line, then just launch infinity polling with your API

This seems to solve this problem, but now all the files I download (mp3 files) are json inside: {"ok":false,"error_code":404,"description":"Not Found"}

and I'm not sure why. I didn't change my code at all, and it worked fine when I was using the telegram API. that's probably the response from requests that I use to get the file. after getting the url from get_file_url

any idea on this? I removed the line of logout like you said, and waited 10 minutes.

coder2020official commented 6 months ago

I think you have to put a slash at the end of the API_URL. Check the original string, I had a similar thing

iti-D commented 6 months ago

I think you have to put a slash at the end of the API_URL. Check the original string, I had a similar thing

Another error came through.. without the slash I get what I got before, no error but when I download files I get this error json.

But now just adding the slash I immediately get error when running the python file: telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 404. Description: Not Found: method not found

also tried replacing localhost with 127.0.0.1 but got the same result..

I do tend to think that the error is in the deploying of the local API server, but I don't know what. I did it the simplest way possible.

docker run -d -p 8081:8081 --name=telegram-bot-api4 --restart=always -v telegram-bot-api-data:/var/lib/telegram-bot-api -e TELEGRAM_API_ID=id -e TELEGRAM_API_HASH=hash -e TELEGRAM_LOCAL=true aiogram/telegram-bot-api:latest

I tried putting TELEGRAM_API_ID in quotes and without, but it didn't seem to change anything...

coder2020official commented 6 months ago

You don't need quotes for specifying parameters afaik Ok, so without a slash - you are getting not found error? Are you sure that the token is right?

iti-D commented 6 months ago

You don't need quotes for specifying parameters afaik Ok, so without a slash - you are getting not found error? Are you sure that the token is right?

without the slash - running the main.py doesn't throw any errors. I can use my bot and it responds regularly.

Now, when I send the command that will download the files I sent - I also get a positive feedback, but that is because my function doesn't care the type of it gets and just downloads it.

def audio_download(links_file):

    with open(links_file, 'r') as file:

        for line in file:
            file_id, title = line.split("@@$#$**#$#@@")
            title = title.rstrip()
            song_url = bot_main.bot.get_file_url(file_id)

            # Downloading and saving song
            response = requests.get(song_url)
            with open(f"{MUSIC_DOWN_PATH['audio']}/{title}", "wb") as file:
                file.write(response.content)

it just writes the content of the response into the file. so when I get a real .mp3 file it's OK. but when the response if error in JSON format, it'll just write that into the file. Only after doing file song.mp3 and seeing it's JSON (and weight 55bytes) did I see the error. Python alone didn't throw any exceptions.

ubuntu@ubuntu ~/tg_bot> cat ~/music/tg_bot/audio/Nightwish\ -\ Taikatalvi.mp3 
{"ok":false,"error_code":404,"description":"Not Found"}⏎ 
coder2020official commented 6 months ago

Oh, you also have to set apihelper.FILE_URL to your local bot API instance url

iti-D commented 6 months ago

Oh, you also have to set apihelper.FILE_URL to your local bot API instance url

I saw this variable in the apihelper file but thought it was just an option to read link from file instead of writing it in the code 😅

what's the "local bot API instance url"? is it just http://localhost:8081 in my case?

coder2020official commented 6 months ago

I can't check it now, but I think it should be equivalent to your API_URL

iti-D commented 6 months ago

I can't check it now, but I think it should be equivalent to your API_URL I looked here https://www.pythonanywhere.com/forums/topic/33464/ they seem to do what you just suggested, I added the following line apihelper.FILE_URL = "http://localhost:8081/"

but I got the same error. tried changing the url to these, but still same error http://localhost:8081 http://localhost:8081/ http://localhost:8081/bot http://localhost:8081/bot/ - this got {"ok":false,"error_code":401,"description":"Unauthorized: invalid token specified"} but I can see why (the token and the word bot shouldn't be seperated) http://localhost:8081/bot{0}/{1}

just to make sure again, the order is this:

bot = telebot.Telebot...
apihelper.API_URL = 
apihelper.FILE_URL = 
# message handlers
bot.infinity_polling()

right?

also thanks for your time so far it is really appreciated.

coder2020official commented 6 months ago

What error did you get when you have set the last one, with numbers?

iti-D commented 6 months ago

What error did you get when you have set the last one, with numbers?

I just got this JSON in my mp3 file: {"ok":false,"error_code":404,"description":"Not Found: method not found"}

coder2020official commented 6 months ago

Can you turn on debug to see what URL is being requested?

coder2020official commented 6 months ago

No need for debug, set the URL to: https://api.telegram.org/file/bot{0}/{1} (Adjust it)

iti-D commented 6 months ago

No need for debug, set the URL to: https://api.telegram.org/file/bot{0}/{1} (Adjust it)

still didn't work.. changed it to "https://api.telegram.org/file/bot{0}/{1}" and also to localhost instead of api.telegram.org same error {"ok":false,"error_code":404,"description":"Not Found"}

should I still turn on debug? also, how do I do it?

coder2020official commented 6 months ago

You have to set it to your localhost(127.0.0.1) with your port Did you do that?

Badiboy commented 6 months ago

@iti-D , let's start from providing proofs that you started local API server correctly.

This post (https://github.com/eternnoir/pyTelegramBotAPI/issues/2243#issuecomment-2079357718) makes me think that you do not know what you are doing.

iti-D commented 6 months ago

You have to set it to your localhost(127.0.0.1) with your port Did you do that?

yep, set it to "http://localhost:8081/file/bot{0}/{1}"

Badiboy commented 6 months ago

Did you launch the bot API server with --local parameter?

No, thanks for asking. I added -e TELEGRAM_LOCAL=true to my docker run command, but I still get the same error of Error code: 400. Description: Logged out

are you sure this is the right order? I get it immediately when running the python file.

for refrence, here's the docker run command: docker run -d -p 8081:8081 --name=telegram-bot-api4 --restart=always -v telegram-bot-api-data:/var/lib/telegram-bot-api -e TELEGRAM_API_ID=<id> -e TELEGRAM_API_HASH=<hash> -e TELEGRAM_LOCAL=true aiogram/telegram-bot-api:latest

image

What's that?

iti-D commented 6 months ago

@iti-D , let's start from providing proofs that you started local API server correctly.

This post (#2243 (comment)) makes me think that you do not know what you are doing.

what proof should I provide? And I admit it is my first time setting up this local api server. Tho it seemed simple enough to just just the docker container image.

I have posted the command used, I'll paste it here again

docker run -d -p 8081:8081 --name=telegram-bot-api6 --restart=always -v telegram-bot-api-data:/var/lib/telegram-bot-api -e TELEGRAM_API_ID=id -e TELEGRAM_API_HASH=hash -e TELEGRAM_LOCAL=true aiogram/telegram-bot-api:latest

the bot does respond to my messages, for example /start and /help, but when I send it the /download_now command, I get said errors (404 not found when retriveing a file)

When I send the bot an audio file, it saves the file_id and the original name in a text file. then, when I want to download those files to the server locally, I use the /download_now command, and then I get these errors. I do get a respond "Audio file_id saved and will be downloaded later!" when sending an audio file. the bot is responding regularly.

iti-D commented 6 months ago

Did you launch the bot API server with --local parameter?

No, thanks for asking. I added -e TELEGRAM_LOCAL=true to my docker run command, but I still get the same error of Error code: 400. Description: Logged out are you sure this is the right order? I get it immediately when running the python file. for refrence, here's the docker run command: docker run -d -p 8081:8081 --name=telegram-bot-api4 --restart=always -v telegram-bot-api-data:/var/lib/telegram-bot-api -e TELEGRAM_API_ID=<id> -e TELEGRAM_API_HASH=<hash> -e TELEGRAM_LOCAL=true aiogram/telegram-bot-api:latest

image

What's that?

i thought to save myself compiling from source the API server, and used this unofficial docker image of this server. https://hub.docker.com/r/aiogram/telegram-bot-api

coder2020official commented 6 months ago

The bot API server seems to be running as it is returning not found error. Please debug as told in the readme, and see the request URL which is causing the error

Badiboy commented 6 months ago

image

https://core.telegram.org/bots/api#using-a-local-bot-api-server

Checked this?

iti-D commented 6 months ago

The bot API server seems to be running as it is returning not found error. Please debug as told in the readme, and see the request URL which is causing the error

2024-04-26 13:43:44,202 (apihelper.py:165 WorkerThread3) DEBUG - TeleBot: "The server returned: 'b'{"ok":true,"result":{"message_id":697,"from":{"id":redacted,"is_bot":true,"first_name":"redacted","username":"redacted"},"chat":{"id":redacted,"first_name":"redacted","username":"redacted","type":"private"},"date":1714139024,"reply_to_message":{"message_id":redacted,"from":{"id":redacted,"is_bot":false,"first_name":"redacted","username":"redacted","language_code":"en"},"chat":{"id":redacted,"first_name":"redacted","username":"redacted","type":"private"},"date":1714139024,"text":"/download_now","entities":[{"offset":0,"length":13,"type":"bot_command"}]},"text":"Downloading on demand all types of links now!"}}''"
starting  audio # my code prints this when starting to download audio...
2024-04-26 13:43:44,202 (apihelper.py:87 WorkerThread3) DEBUG - TeleBot: "Request: method=get url=http://localhost:8081/bot5527340147:{TOKEN}/getFile params={'file_id': 'CQACAgIAAxkBAAICtGYrratWszuKG1Jtjd98h1zOv7h3AAJfFAACoWIYSNsi7vapBGnrNAQ'} files=None"
2024-04-26 13:43:44,204 (apihelper.py:165 WorkerThread3) DEBUG - TeleBot: "The server returned: 'b'{"ok":true,"result":{"file_id":"CQACAgIAAxkBAAICtmYrr4ixzP8aL-p1Cok49QwhPDH0AAJfFAACoWIYSNsi7vapBGnrNAQ","file_unique_id":"AgADXxQAAqFiGEg","file_size":6335592,"file_path":"/var/lib/telegram-bot-api/<here's my bot API key*>/music/file_26.mp3"}}''"
2024-04-26 13:44:04,076 (apihelper.py:165 PollingThread) DEBUG - TeleBot: "The server returned: 'b'{"ok":true,"result":[]}''"
2024-04-26 13:44:04,076 (__init__.py:690 PollingThread) DEBUG - TeleBot: "Received 0 new updates"
2024-04-26 13:44:04,076 (util.py:94 PollingThread) DEBUG - TeleBot: "Task complete"

* it is there as it, without the bot word before it. should it be there? also, still same error with the JSON

iti-D commented 6 months ago

image

https://core.telegram.org/bots/api#using-a-local-bot-api-server

Checked this?

I'll check this out. tho I still prefer the current method, as it doesn't require me to change my code a lot.

Badiboy commented 6 months ago

tho I still prefer the current method, as it doesn't require me to change my code a lot.

https://core.telegram.org/bots/api#getfile

Nobody says this method can work with local API server. May be yes, may be no.

We (you, we) need to check if local API supports it and if anything should be configured.

iti-D commented 6 months ago

tho I still prefer the current method, as it doesn't require me to change my code a lot.

https://core.telegram.org/bots/api#getfile

Nobody says this method can work with local API server. May be yes, may be no.

We (you, we) need to check if local API supports it and if anything should be configured.

well, they do say "Download files without a size limit." so it can make one think you download them the same way. I'll try to work with getfile and see the absolute path and use that instead.

in the debug output I did see a file path returned like: /var/lib/telegram-bot-api/api_token/music/file_26.mp3

it is in the container, so I'll have to mount this path out to the host and then copy the file form there, I suppose.

but in any case, the conclusion from this is that you can't use the get_file_url or download a file by url when using a local API server?

coder2020official commented 6 months ago

Maybe. I haven't really tried. Maybe try to see how it works by using those functions

iti-D commented 6 months ago

Maybe. I haven't really tried. Maybe try to see how it works by using those functions

I used the file path recived from get_file function, and converted it to the mounted path on my host, and then I use it like that in my code. I just copy.

but in any case I see it makes more sense than getting a URL and trying to download from there.

anyway, thanks for you time, and help. even tho eventually we didn't get the get_file_url thingy to work.

coder2020official commented 6 months ago

Well, since the API docs specifically says that it downloads the file after getFile - we can't do anything about it. I rather see it as an advantage. Since your problem is solved, I will close the issue. If you have any further questions, you are welcome to reopen or create a new issue.