🤖 Telegram Bot "Cats & not only" https://t.me/randcatbot
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Azer 1d71e0d89a Stay quiet under flood control whatever the bot was sending
Only a refused photo was handled. A busy group reaches Telegram's limit
of about twenty messages a minute even with each person held to one
picture a second, and from then on the "Не так быстро" reply, /help,
/start and the "unavailable" reply are refused too, as is an inline
answer when the bot as a whole is over its limit. Each of those escaped
its handler, and aiogram logged it at ERROR with a full traceback.

Flood waits are now handled once, by an errors handler on the
dispatcher: one warning line with the wait and what was dropped, e.g.

  flood control for 30 s, SendMessage to chat -100500 was dropped

and nothing else is sent. The photo's flood wait goes the same way. The
new test floods a chat with a burst, /help and an inline query; without
the handler the first refused reply raises out of the dispatcher.
2026-10-13 04:51:48 +04:00
.forgejo/workflows Run the CI on GitHub as well 2026-10-11 16:54:22 +04:00
.github/workflows Run the CI on GitHub as well 2026-10-11 16:54:22 +04:00
screenshots New photos 2020-05-06 12:57:30 +04:00
tests Stay quiet under flood control whatever the bot was sending 2026-10-13 04:51:48 +04:00
.env.example Await the API calls, and stop crashing /start on a current emoji release 2026-10-07 01:11:16 +04:00
.gitignore Keep the .venv the README creates out of git status 2026-10-12 18:49:44 +04:00
animals.py Say at once that cats or dogs are down, not after ten seconds each time 2026-10-12 19:26:37 +04:00
config.py Stop telling groups in /help to type "котик", which does nothing there 2026-10-13 04:21:39 +04:00
lazy_models.py Skip aiogram's eager schema build to start 3x faster in half the memory 2026-10-11 16:53:55 +04:00
LICENSE Create LICENSE 2020-06-03 14:55:17 +04:00
main.py Stay quiet under flood control whatever the bot was sending 2026-10-13 04:51:48 +04:00
README.md Say in the README that inline mode has to be switched on in @BotFather 2026-10-13 04:29:05 +04:00
requirements.txt Move to aiogram 3, so the bot installs on Python 3.12 and newer 2026-10-11 00:54:59 +04:00
throttle.py Limit pictures to one a second per person and chat 2026-10-11 01:17:31 +04:00

Telegram Bot "Котики и не только" ("Cats & not only")

@randcatbot is a Telegram bot, written thanks to the Telegram Bot Api and the Python Aiogram framework. More information about this bot (in Russian) you can read here.

License: MIT

The code has NOT been polished and is provided "as is". There's a lot of code that is redundant and there are tons of improvements that can be made.

Using it

  • котик or собачка in a private chat, or /cat and /dog anywhere: a random picture. In groups only the commands work, because a bot in Telegram's default privacy mode is not shown plain messages there. One picture a second per person and chat; the first request over that is told to slow down, the rest are ignored until the second is up.
  • /help: how to use the bot. The commands are also in the menu next to the input field; the bot sets it on every start.
  • Inline, in any chat: type @randcatbot and pick one of two cats and two dogs. @randcatbot кот (or cat) offers four cats, @randcatbot собака (or dog) four dogs.

Running it

python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
export BOT_TOKEN=...        # from @BotFather; see .env.example
python main.py

Needs Python 3.10 - 3.14, the range aiogram 3 supports.

BOT_TOKEN is read from the environment and the bot refuses to start without it. Nothing reads .env by itself; to use one, copy .env.example to .env, put the token in, and load it with set -a; . ./.env; set +a before python main.py, or hand it to systemd as below.

Only one copy of the bot can run per token: Telegram gives updates to one poller, and a second one gets Conflict: terminated by other getUpdates request. Messages sent while the bot was down are dropped on start, not answered all at once.

Inline mode is off for a new bot, and Telegram sends it no inline queries until it is switched on: send /setinline to @BotFather, pick the bot and give it a placeholder, e.g. кот или собака. The command menu needs nothing there, since the bot sets it itself.

Keeping it running

The bot polls Telegram, so it needs no open port or domain, only outgoing HTTPS. Logs go to stderr. A systemd unit for a checkout in /opt/randcatbot-py owned by a randcatbot user, set up as above, with the token in its .env:

# /etc/systemd/system/randcatbot.service
[Unit]
Description=@randcatbot
Wants=network-online.target
After=network-online.target

[Service]
User=randcatbot
WorkingDirectory=/opt/randcatbot-py
EnvironmentFile=/opt/randcatbot-py/.env
ExecStart=/opt/randcatbot-py/.venv/bin/python main.py
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now randcatbot
journalctl -u randcatbot -f

systemctl stop sends SIGTERM, which stops the polling and closes the connections cleanly.

Tests

python -m unittest -v

They need neither a token nor the network. The handlers run through the real dispatcher against a bot whose HTTP session records every Bot API call instead of sending it (tests/helpers.py), and the animal APIs are mocked.

FAQ

Q: Where exactly does the bot take photos from?

A: Cats come from TheCatAPI and dogs from Dog CEO. When one of them is down, the bot falls back to Cat as a Service or random.dog on its own. Pictures are fetched ten at a time and kept ready, so a request does not wait on any of these APIs.

Q: Why are there no dogs in inline mode?

A: There are now. Inline mode used to send a single random cat; it offers two cats and two dogs, or four of either if the query asks for one.

Q: Is the author obsessed with cats?

A: No... At least I want to believe it....

Screenshots

Screenshot of cat Screenshot of inline cat Screenshot of dog

Author

(C) 2020 by Azer Sadykhzadeh.