telegram-bot
Very powerful module for creating Telegram bots.
Get started
First of all you need to create your bot and get Token, you can do it right in telegram, just write to @BotFather.
Now lets write simple bot!
'use strict'
var tg = require('telegram-node-bot')('YOUR_TOKEN')
tg.router.
when(['ping'], 'PingController')
tg.controller('PingController', ($) => {
tg.for('ping', () => {
$.sendMessage('pong')
})
})
Thats it!
Introduction
I'm using something like MVC, so we have router and controllers.
First you need to declare your commands and which controller will handle it.
Then you need to write controllers and handle specific commands in it.
Router
For example if we want three command: /start, /stop and /restart
And we want that commands to be handled by different controllers.
Router declaration code will be like this:
tg.router.
when(['/start'], 'StartController').
when(['/stop'], 'StopController').
when(['/restart'], 'RestartController')
Probably we will have a case when user send us command we didn't know, for that case router have otherwise function:
tg.router.
when(['/start'], 'StartController').
when(['/stop'], 'StopController').
when(['/restart'], 'RestartController').
otherwise('OtherwiseController')
Now all unknown commands will be handled by OtherwiseController.
Sometimes your commands have some args, you can declire them like this:
tg.router.
when(['/sum :num1 :num2'], 'SumController')
After they will be in 'query' property of scope:
tg.controller('SumController', ($) => {
tg.for('/sum :num1 :num2', ($) => {
$.sendMessage(parseInt($.query.num1) + parseInt($.query.num2))
})
})
Let's say you have some login logic in controller probably you need to route user to login 'page'.
For that case you have routeTo function:
tg.controller('StartController', ($) => {
tg.for('/profile', ($) => {
if(!logined){
$.routeTo("/login")
}
})
})
Controllers
Controllers are very simple:
tg.controller('ExampleController', ($) => {
tg.for('/test', ($) => {
})
tg.for('/example', ($) => {
})
})
Remember: if you want to handle command in controller you need to declare it in router.
Сhain
Let's say you asked user for something, now you need to wait his next message and make some logic, right?
waitForRequest function well help you:
tg.controller('ExampleController', ($) => {
tg.for('/reg', ($) => {
$.sendMessage('Send me your name!')
$.waitForRequest(($) => {
$.sendMessage('Hi ' + $.message.text + '!')
})
})
})
waitForRequest will call callback and pass new context.
Methods
You can call methods two ways:
Directly from tg:
tg.sendMessage(chatId, 'Hi')
Or if you using controllers controller will pass you context '$' than already knows user id, so it's more easy to use:
$.sendMessage('Hi')
All methods have required parameters and optional parameters, you can find them in api documentation
Also all methods have callback parameter, callback returns request result, callback parameter always the last one.
Forms
With $.runForm function you can create forms:
var form = {
name: {
q: 'Send me your name',
error: 'sorry, wrong input',
validator: (input, callback) => {
if(input['text']) {
callback(true)
return
}
callback(false)
}
},
age: {
q: 'Send me your age',
error: 'sorry, wrong input',
validator: (input, callback) => {
if(input['text'] && IsNumeric(input['text'])) {
callback(true)
return
}
callback(false)
}
}
}
$.runForm(form, (result) => {
console.log(result)
})
Bot will ask send the 'q' message to user, wait for message, validate it with your validator function and save the answer, if validation fails bot will ask again that question.
You can create menu with $.runMenu function:
$.runMenu({
message: 'Select:',
options {
parse_mode: 'Markdown'
},
'Exit': {
message: 'Do you realy want to exit?',
resize_keyboard: true,
'yes': () => {
},
'no': () => {
}
},
'anyMatch': () => {
}
})
Layouting menu:
You can pass the maximum number of buttons in line like this:
$.runMenu({
message: 'Select:',
layout: 2,
'test1': () => {},
'test2': () => {},
'test3': () => {},
'test4': () => {},
'test5': () => {},
})
Or you can pass an array of number of buttons for each line:
$.runMenu({
message: 'Select:',
layout: [1, 2, 1, 1],
'test1': () => {},
'test2': () => {},
'test3': () => {},
'test4': () => {},
'test5': () => {},
})
If you pass layout
Bot will create keyboard and send it with your message, when user select if item is callback bot will call it, if it's submenu bot will send submenu.
Scope
As you can see controller methods always give you scope ( $ ).
Scope have:
- all methods with already set chatId
- chatId (current chat id)
- message
- args ( if you have command '/test' and user will send you '/test 1' 'args' will contain 1
- query ( object of args )
Methods List
List of supported methods with required parameters:
sendPhoto(chatId, photo)
sendDocument(chatId, document)
sendMessage(chatId, text)
sendLocation(chatId, latitude, longitude)
sendAudio(chatId, audio)
forwardMessage(chatId, fromChatId, messageId)
getFile(fileId)
sendChatAction(chatId, action)
getUserProfilePhotos(userId)
sendSticker(chatId, sticker)
sendVoice(chatId, voice)
sendVideo(chatId, video)
kickChatMember(chatId, userId)
unbanChatMember(chatId, userId)
sendVenue(chatId, latitude, longitude, title, address, options)
sendContact(chatId, phoneNumber, firstName, options)
editMessageText(text, options)
editMessageCaption(options)
editMessageReplyMarkup(options)
answerCallbackQuery(callbackQueryId)
Additional methods
sendPhotoFromUrl(chatId, url)
sendDocumentFromUrl(chatId, url)
sendAudioFromUrl(chatId, url)
call(method, params)
Additional info
For sendDocument method document parameter need to be like this:
var doc = {
value: fs.createReadStream('file.png'),
filename: 'photo.png',
contentType: 'image/png'
}
$.sendDocument(doc)
For sendPhoto method photo parameter is ReadStream object, example:
$.sendPhoto(fs.createReadStream('photo.jpeg'))
For sendAudio method audio parameter is ReadStream object, example:
$.sendAudio(fs.createReadStream('audio.mp3'))
For sendVoice method voice parameter is ReadStream object, example:
$.sendVoice(fs.createReadStream('voice.ogg'))
For sendVideo method video parameter is ReadStream object, example:
$.sendVideo(fs.createReadStream('video.mp4'))
For sendSticker method sticker parameter is ReadStream object, example:
$.sendSticker(fs.createReadStream('sticker.webp'))
Inline mode
You can handle inline requests with 'tg.inlineMode':
tg.inlineMod(($) => {
})
To answer request you can use 'answerInlineQuery' and 'paginatedAnswer' methods:
tg.inlineMod(($) => {
tg.answerInlineQuery($.id, [{
type: 'gif',
gif_url: 'http://thecatapi.com/api/images/get?format=src&size=med&type=gif&qwe=' + Math.random().toString(36).substring(2),
gif_width: 250,
gif_height: 250,
thumb_url: 'http://thecatapi.com/api/images/get?format=src&size=small&type=gif&qwe=' + Math.random().toString(36).substring(2)
}])
})
'paginatedAnswer' method will care about paging response for you:
tg.inlineMod(($) => {
var results = []
for(var i = 0; i < 51; i++){
results.push({
type: 'gif',
gif_url: 'http://thecatapi.com/api/images/get?format=src&size=med&type=gif&uid=' + Math.random().toString(36).substring(2),
gif_width: 250,
gif_height: 250,
thumb_url: 'http://thecatapi.com/api/images/get?format=src&size=small&type=gif&uid=' + Math.random().toString(36).substring(2)
})
}
tg.paginatedAnswer($, results, 10)
})
'inlineMod' method passes inline scope that consists of update object and 'answer' and 'paginatedAnswer' methods prepared for answer that request.
So this code will be valide too:
tg.inlineMod(($) => {
var results = []
for(var i = 0; i < 51; i++){
results.push({
type: 'gif',
gif_url: 'http://thecatapi.com/api/images/get?format=src&size=med&type=gif&uid=' + Math.random().toString(36).substring(2),
gif_width: 250,
gif_height: 250,
thumb_url: 'http://thecatapi.com/api/images/get?format=src&size=small&type=gif&uid=' + Math.random().toString(36).substring(2)
})
}
$.paginatedAnswer(results, 10)
})
Callback querys
You can handle qallback querys with 'tg.callbackQuerys':
tg.callbackQuerys(($) => {
})
And you can answer them using 'tg.answerInlineQuery' method or using 'answer' method from scope:
tg.callbackQuerys(($) => {
$.answer({text: 'test'})
$.answerInlineQuery($.id, {text: 'test'})
})
License
Copyright (c) 2016 Narek Abovyan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.