It all started with the god damn PlayStation 5. It was launch day here in Israel, and I’ve been trying to find a store that sells one (after missing out on the pre-order). Obviously, they’re hard to come by.
After talking to a few stores, it was clear to me that the supply is limited and I’ll have to wait for restocks to arrive. But how will I know when it’ll happen? Every sales person I’ve spoken to did no know to predict a time. So what am I gonna do? Just call to a store once a day until they’ll have supply? Nope.
When I thought about how to tackle this problem, I thought back to an article I read a few weeks ago, about the usage of scripts as a way to “win at life”, which included as an example a student who wrote a script to alert him when the pre-order of the PS5 is live. And while I missed on that particular train, I figured - why not do the same , and use a scrip to let me know when the console is back in stock?
Design: Telegram Bots + Docker = ❤️
When I went about designing my solution, I’ve defined three main goals:
- Simple to write: I didn’t want to deal with many services, and to have to orchestrate an array of services bouncing alerts from one service to another. I wanted a simple and elegant solution, that will be easy to maintain and debug while remaining easy to use.
- Simple to deploy: Again - I didn’t want to be dealing with a bunch of services that I’ll have to setup, configure, backup and etc. I wanted a solution that will allow me to run a script on a server and be done with it.
- Simple to reuse: If this will prove as an effective method of notifying me when stuff happens, I will want to reuse this project to solve other problems. Therefor, I would like my solution to be easily customisable to allow for simple reuse.
To meet these design goals, I’ve decided to go with Telegram Bots. It’s a technology I’ve used before, and praised for solving the problem of getting a message to my phone in the easiest way possible.
Since Telegram bots already have many libraries that provide an easy API to operate such bots, writing a generic bot in Python should be a walk in the park. And to satisfy goals 2+3, I’ve decided to write the bot as a dockerized application to allow for easy deployments and to avoid dependancies management.
The project I’ve ended with is called WebsiteWatcher, and it’s available under the MIT license over at my GitHub account. For instructions on how to use and deploy it, please use the README. The rest of this post will describe how I wrote it.
Step One: Registering a bot in Telegram
Registering a bot in Telegram is one of the best experiences I could’ve ask for in this situation. No signup forms, no putting in tons of personal information, no explaining the reasons you wish to build a bot for - nothing. Just text @BotFather, choose a name and you’re done. It’s that easy:
Once you’re done, you should receive from BotFather your Telegram Bot’s Token. This token is used by the API to authenticate you as the legitimate operator of the bot, and is the connection between your Python script to the Telegram infrastructure - and that’s why it’s vital to keep it secret and secure.
Step two: Writing the code
There really isn’t much to say about this other than to share the design I came up with for this project:
- The main file is bot.py, which contains most of the logic for the bot side of the code (sending and receiving messages, authenticating the user to avoid randoms using your server resources, etc)
This class keeps a list of watcher objects, derived from a configuration file (more on that in the next bullet), and provides an API for checking updates - using the run_watcher function, the WatcherManager does the work for you and returns a ChangeEvent instance, which contains information about whether or not there was a change, and if so what strings from the user’s interest lists were changed.
- The configuration is stored in a file called config.json, and it looks like this:
this configuration file contains an array of ‘watchers’ each of which is a JSON object containing a URL to monitor changes in and two lists, whitelist and a blacklist (I still have a logical bug there, which results in the blacklist being useless - I’ll solve it soon) which describe what changes are of interest to the user and whether or not there should be a notification for every change, even if it doesn’t involve the user’s strings.
Step three: Deployment
Just kidding. The whole thing is dockerized, so all you need to do is basically:
docker build --tag website-watcher-bot:1.0 . docker run --detach --name website-watcher website-watcher-bot:1.0
The README does a pretty good job of explaining this, so if you’re reading this post in order to understand how to run this project - refer to the README
This was a fun afternoon project for me, and I’m happy I wrote this. I’ve tried my best to write a generic solution, and I believe that my code is concise and well documented - a project to be proud at. Oh, and it also works (which is important, I guess).
Hopefully, I’ll also get a PS5 out of the deal sometime.
A note about privacy
Telegram isn’t known for being the most private and secure texting app out there. I’m using it, but I wouldn’t use this platform or it’s bot services for anything you wouldn’t want anybody reading.
I've written a follow-up for this post, in which I explain about changes I made to this project - including the ability to receive notifications via Phone calls. Check it out!