/src/program.js
JavaScript | 490 lines | 389 code | 50 blank | 51 comment | 75 complexity | e9019e0cab3082e99d4d38566f40fcda MD5 | raw file
- // Require modules
- var botgram = require('botgram');
- var Forecast = require('forecast');
- var cool = require('cool-ascii-faces');
- var Pokedex = require('pokedex');
- var isUp = require('is-up');
- var leet = require('l33tsp34k');
- var predict = require('eightball');
- var Datastore = require('nedb');
- var request = require("request-promise");
- var clor = require("clor");
-
- // Load variables
- var config = require('./config');
- var pokedex = new Pokedex();
-
- // Initialise db
- var db = new Datastore({ filename: 'datastore.js', autoload: true });
-
-
- // Initialise the forecast.io component
- var forecast = new Forecast({
- service: 'forecast.io',
- key: config.forecast,
- units: 'celcius', // Only the first letter is parsed
- cache: true, // Cache API requests?
- ttl: { // How long to cache requests. Uses syntax from moment.js: http://momentjs.com/docs/#/durations/creating/
- minutes: 27,
- seconds: 45
- }
- });
-
- // Initialise geocder
- var geocoder = require('node-geocoder')(config.geocode.provider, 'https', {apiKey: config.geocode.apiKey});
-
- // Setup the bot settings
- var options = {
- polling: true
- };
-
- // Initialise the bot.
- var bot = botgram(config.token);
-
- console.log("The bot is up and running!");
-
- // ###################
- // # COMMAND SECTION #
- // ###################
-
- // Spam protection, only for commands in regex
- bot.command(/(forecast|joke|pokedex|isup)/, function (msg, reply, next) {
- spamProtect(msg, function(blocked, cmdcount){
- if(!blocked){
- if(cmdcount >= 4){
- reply.text(`Take a break ${(msg.from).name}, or you will be blocked!`);
- }else{
- next();
- }
- }else if(cmdcount == 5){
- reply.text(`${(msg.from).name}, you have been blocked!`);
- }
- });
- });
-
-
- // /start & /help - Displays help information
- bot.command("start", "help", function (msg, reply, next) {
- logFunc(msg);
- var helpConf = config.help;
- if(helpConf != ""){
- reply.text(config.help);
- }
- });
-
- // /echo - Echos the given text to the user
- bot.command("echo", function (msg, reply, next) {
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /echo [text]");
- return;
- }
- reply.text(args);
- });
-
- // Catch locations in chat and give forecast for that location
- bot.location(function(msg, reply, next){
- logFunc(msg);
- getForecast(msg.latitude,msg.longitude, undefined, undefined, function(str){
- reply.text(str);
- });
- });
-
- // /forecast [place] - Gives forecast for location
- bot.command("forecast", function (msg, reply, next) {
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /forecast [location]");
- return;
- }
-
- geocoder.geocode(args, function(err, res){
- if(err){
- // something went wrong
- return;
- }
- if(res.length == 0){
- reply.text("Cannot find the place you are looking for.");
- return;
- }
- getForecast(res[0].latitude,res[0].longitude, res[0].city, res[0].country, function(str){
- reply.text(str);
- });
-
- });
- });
-
- function getForecast(lat,long, city, country, callback){
- forecast.get([lat,long], function(err, weather){
- if (err){
- callback("Could not find weather data for this location.");
- }
- if(country === undefined){
- var respString = "The weather at the given location is " + weather.currently.summary
- + " with a temperature of " + weather.currently.temperature + "°C";
- }else{
- var respString = "The weather in "+ city + ", " + country+" is " + weather.currently.summary
- + " with a temperature of " + weather.currently.temperature + "°C";
- };
- callback(respString);
- });
- }
-
- // /pokedex - Pokedex, find pokemon by name or id
- bot.command("pokedex", function(msg,reply,next){
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /pokedex [id / name]");
- return;
- }
- var result = pokedex.pokemon(args);
-
- // Check if found name
- if(result.id === undefined){
- result = pokedex.pokemon(parseInt(args));
- }
- // Check if found ID
- if(result.id === undefined){
- reply.text("No pokemon found with that ID/name.");
- return;
- }
- var respString = "ID: " + result.id
- + "\r\nName: " + result.name
- + "\r\nHeigth: " + result.height
- + "\r\nWeight: " + result.weight;
- if(result.sprites.animated){
- reply.text(result.sprites.animated);
- }else if(result.sprites.normal){
- reply.text(result.sprites.normal);
- }
-
- reply.text(respString);
-
- });
-
- // /ishetaltijdvoorbier
- bot.command("ishetaltijdvoorbier", function(msg,reply,next){
- logFunc(msg);
- var strings = ["Het is altijd tijd voor bier!",
- "Nu al? Tuurlijk, waarom niet!",
- "Biertje moet kunnen.",
- "Het is ergens 12 uur geweest, toch?"];
- reply.text(strings[Math.floor(Math.random()*strings.length)]);
- });
-
- // /isup - Checks if given hostname is up
- bot.command("isup", function(msg,reply,next){
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /isup [hostname]");
- return;
- }
- isUp(args).then(up => {
- if(up){
- reply.html("It looks like <strong>" + args + "</strong> is <strong>up</strong> from here!");
- }else{
- reply.html("It looks like <strong>" + args + "</strong> is <strong>down</strong> from here.");
- }
- });
- });
-
- // /cool - Displays a cool face
- bot.command("cool", function(msg, reply, next){
- logFunc(msg);
- reply.text(cool());
- });
-
- // /doekoe
- bot.command("doekoe", "moneyz", "stacks", function(msg,reply,next){
- logFunc(msg);
- var respString = `Het aantal dagen kan licht afwijken!\r\n`;
- var sah = getDaysTillNextDay(8);
- var zorgToeslag = getDaysTillNextDay(20);
- var stufi = getDaysTillNextDay(24);
- if(sah == 0){
- respString += `\r\n*Salaris van studentaanhuis komt vandaag!*`;
- }else{
- respString += `\r\nSalaris van studentaanhuis komt over ${sah} dagen.`;
- }
- if(zorgToeslag == 0){
- respString += `\r\n*Zorgtoeslag komt vandaag!*`;
- }else{
- respString += `\r\nZorgtoeslag komt over ${zorgToeslag} dagen.`;
- }
- if(stufi == 0){
- respString += `\r\n*Stufi komt vandaag!*`;
- }else{
- respString += `\r\nStufi komt over ${stufi} dagen.`;
- }
- reply.markdown(respString);
- });
-
- // Gives the days until the next time this date comes (0 for today)
- function getDaysTillNextDay(day) {
- var today, nextDay, diff, days;
- today = new Date();
- nextDay = new Date(today.getFullYear(), today.getMonth(), day, today.getHours(), today.getHours(), today.getMinutes()+1);
- if(today.getDate() == day){
- return 0;
- }
- if(today.getTime() > nextDay.getTime()){
- nextDay.setMonth(nextDay.getMonth()+1);
- }
- diff = nextDay.getTime() - today.getTime();
- days = Math.round(Math.abs(diff/(1000*60*60*24)));
- return days;
- }
-
- // /leet
- bot.command("leet", function(msg,reply,next){
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /leet [string]");
- return;
- }
- reply.text(leet(args));
- });
-
- // /8ball
- bot.command("8ball", "magic8ball", function(msg,reply,next){
- logFunc(msg);
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /8ball [yes/no question]");
- return;
- }
- reply.text(predict());
- });
-
- // /joke
- bot.command("joke", function(msg,reply,next){
- logFunc(msg);
- var url = 'https://www.reddit.com/r/jokes/.json';
- request(url)
- .then( data => {
- var parsed = JSON.parse(data).data.children,
- l = parsed.length,
- n = Math.floor(Math.random() * (l - 1)) + 1,
- title = parsed[n].data.title,
- selftext = parsed[n].data.selftext;
- console.log("\n"+clor.blue.underline(title));
- console.log(clor.yellow(selftext)+"\n\n\n");
- reply.markdown("*" + title + "*\r\n" + selftext);
- })
- .catch( err => {
- console.warn(err);
- });
-
- });
-
- // /info
- bot.command("info", function(msg, reply, next){
- logFunc(msg);
- reply.markdown("*Source is available here:*\r\nhttps://git.sprofix.com/guyspronck/node-telegram-bot\r\n\r\n"
- + "Have an idea for a cool command? Check the [issue tracker](https://git.sprofix.com/guyspronck/node-telegram-bot/issues) if it has already been requested, or request is yourself!"
- + "\r\n_Please use labels to mark your issue/request!_");
- });
-
- // /stats
- bot.command("stats", function(msg, reply, next){
- getStats(msg, function(response){
- reply.html(response);
- });
- });
-
-
- // #############
- // # SUPERUSER #
- // #############
-
- // /su - Simple superuser check
- bot.command("su", function (msg, reply, next) {
- logFunc(msg);
- if((config.superusers.indexOf((msg.from).id) == -1)){
- reply.text("You do not deserve my greetings, pleb.");
- }else{
- reply.text("I greet you master.");
- }
- });
-
- // /block - Toggles the user block
- bot.command("block", function (msg, reply, next) {
- logFunc(msg);
- // Check for access
- if((config.superusers.indexOf((msg.from).id) == -1)){
- return;
- }
- // Check args
- var args = msg.args();
- if (args.trim().length == 0) {
- reply.text("Usage: /block [userid]");
- return;
- }
- db.findOne({ userid: parseInt(args)}, function(err, doc){
- if(doc == null){
- reply.text("Userid not found.");
- }else{
- doc.blocked = !doc.blocked;
- db.update({ userid: parseInt(args)}, doc, {}, function(err, numReplaced){
- });
- reply.text("The block for the given user has been toggled.");
- }
- });
- });
-
- // ###########
- // # GENERIC #
- // ###########
-
- // Command not found...
- bot.command(function (msg, reply, next) {
- reply.text("Invalid command, oops!");
- });
-
- // Used for stats tracking
- bot.message(function (msg, reply, next) {
- updateStats(msg);
- });
-
- // ####################
- // # FUNCTION SECTION #
- // ####################
-
- function getStats(msg, callback){
- if((msg.chat).type == 'group' || (msg.chat).type == 'supergroup'){
- db.findOne({ chatid: (msg.chat).id}, function(err, doc){
- if(doc == null){
- callback("No stats for this chat yet, start talking!");
- return;
- }
- var response = `Stats for <strong>${(msg.chat).title}</strong>:\r\n`;
- var totalmsgs = 0;
- doc.users.sort(function(a,b){
- return b.msgcount - a.msgcount;
- });
- for(var i = 0; i < doc.users.length; i++){
- var firstname = doc.users[i].firstname !== undefined ? doc.users[i].firstname + " " : "";
- var lastname = doc.users[i].lastname !== undefined ? doc.users[i].lastname + " " : "";
- var username = doc.users[i].username !== undefined ? doc.users[i].username : "";
- response += `\r\n${firstname}${lastname}(${username}): <strong>${doc.users[i].msgcount}</strong>`
-
- totalmsgs += doc.users[i].msgcount;
- }
- response += `\r\n\r\nTotal messages: <strong>${totalmsgs}</strong>`;
- callback(response);
- });
- }else{
- callback("Stats are only available in (super)groups, get some friends!");
- }
- }
-
- function updateStats(msg){
- if((msg.chat).type == 'group' || (msg.chat).type == 'supergroup'){
- db.findOne({ chatid: (msg.chat).id}, function(err, doc){
- if(doc == null){
- // Need to create it now!
- db.insert({chatid: (msg.chat).id, users:[]}, function(err){
- if(err){
- console.log("Error saving stats.");
- }
- });
- updateStats(msg);
- }else{
- // It exists, add stuff to it!
- var foundUser = false;
- for (var i = 0; i < doc.users.length; i++) {
- if(doc.users[i].id == (msg.from).id){
- foundUser = true;
- doc.users[i].msgcount++;
- doc.users[i].username = (msg.from).username;
- doc.users[i].firstname = (msg.from).firstname;
- doc.users[i].lastname = (msg.from).lastname;
- }
- }
-
- // User does not exist yet, save him
- if(foundUser == false){
- doc.users.push({
- id: (msg.from).id,
- msgcount: 1,
- username: (msg.from).username,
- firstname: (msg.from).firstname,
- lastname: (msg.from).lastname
- });
- }
-
- // Updated doc needs to be saved
- var docid = doc._id;
- delete doc['_id'];
- db.update({chatid: doc.chatid}, doc, { }, function(err, numReplaced){
-
- });
- }
- });
- }
- }
-
- function spamProtect(msg, callback){
- console.log("spamProtect");
- if((config.superusers.indexOf((msg.from).id) != -1)){
- callback(false, 1);
- return;
- }
- db.findOne({ userid: (msg.from).id}, function(err, doc){
- if(doc == null){
- db.insert({userid: (msg.from).id,
- blocked: false,
- cmdcount: 0,
- lastcmd: msg.date}, function(err){
- if(err){
- console.log("Error saving spamProtect msg.");
- }
- callback(false, 1);
- });
- }else{
- if(doc.blocked){
- // User is blocked
- callback(true, 0);
- return;
- }
- // if it's been 10 sec since last command, reset counter
- if((new Date().getTime() - doc.lastcmd.getTime()) > 10000){
- doc.lastcmd = msg.date;
- doc.cmdcount = 0;
- db.update({ userid: (msg.from).id}, doc, {}, function(err, numReplaced){
- });
- callback(false, 0);
- }else{
- if(doc.cmdcount >= 5){
- doc.blocked = true;
- db.update({ userid: (msg.from).id}, doc, {}, function(err, numReplaced){
- });
- callback(true, 5);
- }else{
- doc.cmdcount++;
- db.update({ userid: (msg.from).id}, doc, {}, function(err, numReplaced){
- });
- callback(false, doc.cmdcount++);
- }
- }
- }
- });
- }
-
- function logFunc(msg){
- if(msg.type == 'location'){
- console.log(`[${msg.date.toLocaleString('en-GB')}]: Got a location, returning forecast (From: ${(msg.from).name})`);
- return;
- }
- console.log(`[${msg.date.toLocaleString('en-GB')}]: ${msg.text} (From: ${(msg.from).name} ${(msg.from).id})`);
- }
-
- process.on('uncaughtException', function(err) {
- // handle the error safely
- console.log(err)
- })