Late Night Linux Telegram News Bot

On the Late Night Linux podcast we talk about goings on in the Linux and Open Source ecosystem. To keep ourselves in sync we have a Telegram group where we share links to interesting articles.

Telegram does allow you to see an overview of all links sent to that channel but it’s impossible to tell the difference between something we were just commenting on and an article which we think should go in the show.

So we created this Telegram bot to allow us collect interesting links and put them in a spreadsheet where we can review them and more easily copy them over to the show notes.

I didn’t want to have to maintain any infrastructure for this bot, so Google Apps Script seemed like a reasonable choice since we already use Google Docs and Google Drive to manage the rest of our shared files.

The script is available in this Github repo. The file is called appsscript.gs.

Technologies involved

  1. Telegram Bot
  2. Google Docs
  3. Google Apps Scripts

Telegram

You’re going to need to go and see The Botfather and create a new bot. This guide covers most things. The bot doesn’t need to support any commands, we can do that in our script.

The bot should be set up so that it can be added to a group (Allow Groups) and Privacy mode should be enabled so that it can’t read all your other chat.

The Botfather will give you an API key. Keep this to hand.

The bot will interact with the Google Docs spreadsheet via a webhook. That is to say whenever you talk to the bot via a / command the bot will receive the text of the message and POST it to a webhook URL. Google Apps Script will host that URL. We will tell The Botfather about that webhook URL later on. In the meantime create a group chat and invite the bot. We need the chat id for that group so we can test.

To get a chat ID I suggest that you:

  • Open the Telegram web app in your browser
  • Start a new group give it a name and add the bot you created earlier (note, there will probably be 100 “googledocstestbot” bots, make sure you select yours.
  • Note in the URL bar a negative number at the end of the address, this is the chat ID for your 1:1 conversation with the bot. Copy this in to the script in the doPost function. NB: include the minus.

Google Docs

Create a blank Google Docs Spreadsheet. You can lock this down as much as you want. The script will run as you, so you don’t need to leave it open to the world.

Inside the Spreadsheet click Extensions -> Apps Script. This will take you to the Apps Script editor which is where the real work begins.

We will scope the script so that it can only talk to the spreadsheet in which it was created. That is, the script will not have access to the rest of your documents in Google Drive.

Google Apps Script

Google Apps script is more or less Javascript. You can write a script and then deploy it as a web app. This will give you a unique URL which should be kept secret ideally. You need to tell your Telegram bot about that URL and it will POST a JSON object to that URL each time it receives a command (not all messages in the group will be sent to the bot, so it won’t snoop on your normal conversations).

I found it extremely frustrating to test and debug this Apps Script. In order to test you have to deploy it each time which takes a few seconds and a lot of clicking, plus the logging doesn’t seem work at all, so you’re left with few options to see what’s going on. The best way to debug is to stub out the bits which would be POSTed to you from Telegram and then use the Run option at the top of the editor to execute the main doPOST function. That way you do get logs and you don’t have to wait to deploy each time. More on this later.

The Script itself

We need to declare few things:

  • The Telegram bot’s authentication token (the Botfather will give you this)
  • The id of the deployed Apps Script web app. More on this below.
  • A link to the spreadsheet for convenience purposes (not strictly required)
  • A list of Telegram user ids of people who should be allowed to talk to the bot

Writing a row to the spreadsheet

The script will be scoped to a single spreadsheet, this makes writing a row a little easier. All you need to do is:

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  sheet.appendRow(["An","array","of","cells","to","add"]);

this will add a row at the bottom of the first sheet inside the spreadsheet where this script is running. Each element of the array is a cell in the spreadsheet.

Telling Telegram where this script lives

Telegram needs to be updated with the live URL of this script. That URL changes each time you deploy. There is a convenience function to help you manage this called setWebhook. To get this URL you have to (more on this below):

  1. Deploy the script
  2. Copy the deployment id and update the variable at the top of the script
  3. In the Apps Script editor choose the setWebhook function and click run image

This will simply tell Telegram where to POST messages. You do not need to deploy the script again when you change the deployment id, just run the function, but if you do have to redeploy the script the ID will change and you will have to update the script with that id and rerun the setWebhook function.

Sending Telegram messages

We use the JSON object method on the sendMessage Telegram API to send messages. The sendMessage function builds a suitable payload and POSTs it.

The main function doPost

The doPost function is called when Telegram POSTs a JSON object containing information about the message it received to the webhook URL. We unpack that object, pick out the relevant information, do some basic sanity checking, add the URL to the spreadsheet and send back a confirmation message.

This is where you need to set some static values if you want to test and debug in the Apps Script editor. Rather than actually POSTing an object we use a local variable instead.

Testing the function

As mentioned above, testing Apps Scripts of this type is painful. The best way I found to do it was to replace the data that Telegram would normally POST with hardcoded variables. This allows you to run a single function from the UI and get logging output and errors. I’ve left comments in the code where you can do this. You will need to change some bits to suit you. Keep reading for more information on this.

When you run the script for the first time you will be asked to verify a few things. The process looks like this:

After changing the code to uncomment the test bits. select “doPost” and click “Run”. image

Click “Review Permissions” image

Choose your Google account image

Deal with this massive warning by clicking “Advanced”, and then “Go to <your script name” image

Note that the script can only interact with the single spreadsheet you created, plus “connect to an external service” (i.e. POST back to Telegram to send messages): image

If everything works you should see a message from the bot in the Telegram group you created and a new line in the spreadsheet. You are now ready to deploy this script, get a webhook URL and hook it up to the bot. If not, you should at least have some useful logging messages and errors.

Deploying the script

You now need to comment out all the testing variables and uncomment out the code which gets those values from the POSTed data from Telegram. Do this and save. image

At the top right you have a “Deploy” button. Click that and choose “New Deployment”.

Then you have to deal with this rather opaque dialogue: image

Click the cog next to “Select Type” (yes, it does look like a column header and not a button) and choose “Web App”: image

Fill out the form. Give it a name, allow it to run as you (it’s easier) and allow “Anyone” access: image

Click “Deploy”, and you will get back some info. Copy the “Deployment ID” to the clipboard.

image

Take that id and at the top of the script set webAppId to be that value. Save the script (ctrl-s). At the top from the function dropdown choose setWebhook and click run image

That will tell Telegram where to POST it’s messages.

Once the script is deployed back in the group chat you posted earlier you should now be able to instruct the bot directly by typing: /news <url> and after a few seconds the URL should appear in the spreadsheet and you will receive a confirmation message back from the bot.

Conclusion

Despite its clunkiness when writing a web app Google Apps Script is powerful enough to be able to develop some useful functionality and the Telegram bot API is simple enough to make that easy. I’ll be interested to hear about bots you create in this way. Get in touch