Building a Telegram bot for Joplin in 15 minutes 🤖
Tags: productivity, telegram, bot, node
Published: 2020-05-12 11:49:51

Everybody is trying to make their lives better and be organized using several productivity apps. So do I. And personally, I'm a man *who lives in a digital notebook*.

It has been a while that I'm searching for alternatives to MS OneNote, the tool I use for last 5 years. But time to move on for me. I decided to move into Joplin. It has its pros and cons but I'm not here to talk about comparing note taking apps. I was playing around with Joplin past several days, and I can say that I'm satisfied with its features.

Anyways, I do a lot of work related research on my phone. I mean, A LOT! I put the resources I found to Google Keep, MS To-do. Sometimes, I like a content on Twitter to come back and read later. Sometimes, I send a message to myself to not forget about something and so on... This became more and more disaster for me, using countless tools and different platforms. It's all became frustrating. So I began to consolidate all of this incoming information to my Joplin notebook. When it comes to dealing information on mobile phone, I want simplicity and quickness. So, playing with [Joplin API](https://joplinapp.org/api/) (which is used by its screen clipper app), I wanted to create a Telegram bot, which I can handle my notebook using my phone.

## Idea
It has been a few months that I'm using Telegram, and I like its bots, very useful like any other bots 😃. You can ask for anything and get the answer back immediately. So I thought it would be great if I can communicate with my notebook via Telegram messages. After a quick research, I saw it is possible!

## First things first! Install Joplin!
The easiest step of this walk-through! Just go to [joplinapp.org](https://joplinapp.org/) and hit download! After installing it (you can also use the portable app), open the app, go to **Tools** > **Options** and then jump to the **Web Clipper** tab.

![Clipper Service](https://dev-to-uploads.s3.amazonaws.com/i/wbrcsx68cj83qjxntzxj.png)

Click the "Enable Web Clipper Service" button and ta-da! You have a JSON web service, serving at 41184 port, that you can communicate with your notebook. You have authorization token down below the page. Note that token, we'll be using it!

![Advanced Settings](https://dev-to-uploads.s3.amazonaws.com/i/057fahj4hub4oz2jikbk.png)

Before we move on, let's test our web service. Open an app like postman and make a GET request to this URL: *http://localhost:41184/notes?token={your_token}*

![request to notes](https://dev-to-uploads.s3.amazonaws.com/i/t5567dmjl7wd7x4wcbyj.png)

Looks nice! We have our notes via web service!

## Create the Telegram bot!
The second easiest part. Let's chit-chat to Telegram's [@BotFather](https://t.me/botfather). Father welcomes us with the information we need. Let's create our bot with answering [@BotFather](https://t.me/botfather)'s questions.

![creating bot conversation](https://dev-to-uploads.s3.amazonaws.com/i/qaspxv27r0abfim5rm4p.png)

Okay, our bot is ready! Let's do some coding to make our bot work as we want.

## Let's create a simple nodejs application
Open your console, type `npm init`, give your application a name and finish the wizard. We are going to use 2 dependencies for our bot. [telegraf.js](https://telegraf.js.org/) for communicating with Telegram, [axios](https://github.com/axios/axios) to make http calls to Joplin's web service. Let's install them as below:
```
npm install telegraf --save
npm install axios --save
```
Create an `index.js` file on the root of your project directory and check out documentation on [telegraf.js](https://telegraf.js.org/) for 5 minutes. 

```javascript
const { Telegraf } = require('telegraf')

const bot = new Telegraf(process.env.BOT_TOKEN)
bot.start((ctx) => ctx.reply('Welcome'))
bot.help((ctx) => ctx.reply('Send me a sticker'))
bot.on('sticker', (ctx) => ctx.reply('👍'))
bot.hears('hi', (ctx) => ctx.reply('Hey there'))
bot.launch()
```
These lines tell us that the bot will welcomes user with the message *Welcome*. If the user sends the command `/help`, bot will reply *Send me a sticker*. If the user sends a sticker, bot will reply with a 'thumbs up' emoji, and if the user says `hi`, bot will reply *Hey there*.

Okay, I want my bot to create a note with the content of the message (if it's a text message). For that, we'll be using `bot.on('text', (ctx) => {...}`. And I can send image files, so if it receives an image file, I want it to create a note titled with caption of the image and put the image in the note. For that, we'll be using `bot.on('photo', (ctx) => {...}`.

First, we define a `Note` class. According to the [Joplin API](https://joplinapp.org/api/), create requests should have the following data (*title*, *body*, *base64_image*). We create a function to set note's image via incoming photo, if available.

```javascript
class Note {
  constructor(title, body) {
    this.title = title
    this.body = body
    this.image_data_url = null
  }

  async setImageData(ctx) {
    if (ctx.message.photo) {
      // get largest possible
      let largest = ctx.message.photo.reduce((prev, current) => (+prev.width > +current.width) ? prev : current)
      let image_url = await ctx.telegram.getFileLink(largest.file_id)
      let image_result = await axios.get(image_url, { responseType: 'arraybuffer' });
      this.image_data_url = "data:image/png;base64," + Buffer.from(image_result.data).toString('base64');
    }
  }
}
```
Then, we configure our bot to communicate with our Joplin notebook as follows.

```javascript
const { Telegraf } = require('telegraf')
const axios = require('axios');

const bot = new Telegraf("your_telegram_token")
const request_url = 'http://localhost:41184/notes?token={your_joplin_token}'

bot.start((ctx) => {
  ctx.reply('Welcome to your Joplin notebook!, just type /help for available commands 😊')
})
bot.help((ctx) => ctx.reply('Use /notes to gel all your notes, or send a text or image message to create a note...'))
bot.command('notes', async ctx => {
  let notes = await axios.get(request_url)
  ctx.reply(notes.data.map(p => p.title).join('\n'))
})
bot.on('text', async ctx => {
  let note = new Note(ctx.message.text.slice(0, 255), ctx.message.text)
  await axios.post(request_url, note)
  ctx.reply('You created a new text note successfully!')
})
bot.on('photo', async ctx => {
  let caption = ctx.message.caption ? ctx.message.caption : 'No title'
  let note = new Note(caption, caption, ctx.message.photo)
  await note.setImageData(ctx)
  await axios.post(request_url, note);
  ctx.reply('You created a new image note successfully!')
})
bot.launch()
```

## Let's talk with Joplin 😊

![texting on telegram](https://dev-to-uploads.s3.amazonaws.com/i/ekmgzgj52u7385nxccj0.gif)

We are all set! Run `node index.js` or hit F5 (on vscode) to run application. Our bot now can handle text messages to create notes and image messages to create image notes. I pushed this code to [this Github repo](https://github.com/hasangok/telegram-bot-for-joplin). I'll hopefully be adding more features like searching via keyword, get note details, tag notes etc if I can make time. Contributions are always welcome 😊

I know Joplin has sync features and a mobile app, but it's good to communicate with somebody even if it's a bot, especially in these days, right? 😉

Thanks for reading!
Hasan