diff --git a/README.md b/README.md index dd3a6fe..28de746 100644 --- a/README.md +++ b/README.md @@ -6,29 +6,24 @@ A Facebook bot for Telegram. ## Install - Create your Telegram bot, follow the instruction [here](https://core.telegram.org/bots#3-how-do-i-create-a-bot). -- Clone this repository and install nodejs package. +- Clone this repository. +- Install nodejs package. ``` -git clone https://github.com/Liryna/FacebookBot.git cd FacebookBot npm install ``` -- Create the configuration file `config.json`. -``` -{ - "email": "YOUR EMAIL", - "password": "YOUR PASSWORD", - "dir": "FacebookBot DIRECTORY" -} -``` + ##Usage -- This bot require some additional information in the your environment variables. +- This bot requires some additional information in your environment variables. ``` -TELEGRAM_USER="your telegram login" -APP_TOKEN="the token of your bot that BotFather gave you" +TELEGRAM_USER_ID="your telegram user id" +TELEGRAM_TOKEN="the token of your bot that BotFather gave you" +FACEBOOK_USERNAME="your facebook username" +FACEBOOK_PASSWORD="your facebook password" ``` - Run it. ``` -TELEGRAM_USER="Mario" APP_TOKEN="TOKEN" node facebookbot.js +node facebookbot.js ``` - The bot cannot establish a conversation to you directly, you need to write him first. Use your Telegram Client to say him "Hello". - The Available commands to send to your bot: @@ -39,4 +34,4 @@ TELEGRAM_USER="Mario" APP_TOKEN="TOKEN" node facebookbot.js ## Dependencies -This bot use [Schmavery/facebook-chat-api](https://github.com/Schmavery/facebook-chat-api) and [depoio/node-telegram-bot](https://github.com/depoio/node-telegram-bot). +This bot use [ravkr/facebook-chat-api](https://github.com/ravkr/facebook-chat-api) and [yagop/node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api). diff --git a/facebookbot.js b/facebookbot.js index d8b0d84..7ebeab8 100644 --- a/facebookbot.js +++ b/facebookbot.js @@ -1,11 +1,11 @@ var fs = require('fs'); -var Bot = require('node-telegram-bot'); +var Bot = require('node-telegram-bot-api'); var login = require("facebook-chat-api"); -if (!process.env.TELEGRAM_USER || !process.env.APP_TOKEN) - return console.log("Please define this env variables -- TELEGRAM_USER - APP_TOKEN"); +if (!process.env.TELEGRAM_USER_ID || !process.env.TELEGRAM_TOKEN) + return console.log("Please define this env variables -- TELEGRAM_USER_ID - TELEGRAM_TOKEN"); -var owner = {username: process.env.TELEGRAM_USER, chat_id: process.env.CHAT_ID || undefined}; +var owner = {username: process.env.TELEGRAM_USER_ID, chat_id: process.env.CHAT_ID || undefined}; var maxThreadNb = 10; function getUsage() { @@ -14,166 +14,222 @@ function getUsage() { + "Available commands:\n" + "/threadlist - List the latest conversations you had with your friends.\n" + "/cancel - Cancel the current command.\n" - + "\n\nMore Informations: https://github.com/Liryna/FacebookBot"; + + "\n\nMore Informations: https://github.com/Kreastr/FacebookBot"; } -var chat = new Array(); +var botWorkingDir = process.env.FACEBOOK_BOT_DIR || (__dirname + "/data"); + +//when a Facebook message is fowarded to user: +//key = TG message id, value = FB thread id +var chat = new Map(); var friends = {}; var threadListTmp; var currentThreadId; -var config; -config = JSON.parse(fs.readFileSync('config.json', 'utf-8')); +// Start Telegram Bot +var bot = new Bot(process.env.TELEGRAM_TOKEN, {polling: true}); -login({email: config.email, password: config.password}, async function (err, api) { - if (err) return console.error(err); - await retrieveFriendsFromFacebook(api); - - //listen telegram message - var bot = new Bot({ - token: process.env.APP_TOKEN - }).on('message', async function (message) { - if (message.from.username != owner.username) - bot.sendMessage({ - chat_id: message.chat.id, - text: "You are not my owner! Go away ! \n" - + "- https://github.com/Liryna/FacebookBot" - }); - else { - if (owner.chat_id == undefined) - owner.chat_id = message.chat.id; //save owner chat id - TODO save in config file - if (!!message.reply_to_message - && !!chat[message.reply_to_message.message_id]) { //it is a reply message from FB +var api = undefined; +var fbReady = false; - api.sendMessage(message.text, - chat[message.reply_to_message.message_id], function (err, api) { - if (err) return console.error(err); - }); +function initFBlistener(){ + api.listen(function callback(err, message) { + if (err) { + console.error("Errors on facebook listening", err); + } + else if (message) { + console.log("Got FB message") + console.log(message) + // gets the fb user name given his id + const senderName = friends[message.senderID] || message.senderID; + + if (message.attachments.length > 0) { + sendAttachmentsToTelegram(bot, senderName, message); + } else { + sendTextMessageToTelegram(bot, senderName, message, message.body); + } } else { + console.log("no message from facebook"); + } + + }); +} + - if (message.text == "/threadlist") { - api.getThreadList(0, maxThreadNb, function callback(err, arr) { +//listen telegram message + + +function doAuth(msg) +{ + console.log("New message in Telegram") + console.log(msg) + if (msg.from.username== owner.username) + { + if (owner.chat_id == undefined) + { + owner.chat_id = msg.chat.id; + console.log("Late start for FB listener") + if (fbReady) + initFBlistener(); + } + return true; + } + bot.sendMessage( ""+msg.chat.id, "I don't know you, "+msg.from.username); + return false; +} + +function initListeners() +{ + bot.onText(/\/echo (.+)/, (msg, match) => { + const chatId = msg.chat.id; + const resp = match[1]; // the captured "whatever" + if (!doAuth(msg)) return; + // send back the matched "whatever" to the chat + bot.sendMessage(chatId, resp); + }); + + bot.onText(/\/threadlist/, (msg, match) => { + const chatId = msg.chat.id; + if (!doAuth(msg)) return; + + api.getThreadList(maxThreadNb, null, [],function callback(err, arr) { + if (err) + return console.error(err); + console.log("got FB Threads List") + console.log(arr) var ft = require('./lib/findThread'); - var fbids = ft.getParticipantsIds(arr); + var fbids = [].concat.apply([], arr.map(el => el.participantIDs)); //Extract IDs and merge them into a single array currentThreadId = undefined; //reset current thread api.getUserInfo(fbids, function (err, ret) { if (err) return console.error(err); - ft.createThreads(arr, ret, function (conversatioNames, newThreadListTmp) { + ft.createThreads(arr, function (conversatioNames, newThreadListTmp) { threadListTmp = newThreadListTmp; - bot.sendMessage({ - chat_id: message.chat.id, - text: "Who is the recipient ?", + bot.sendMessage(msg.chat.id, "Who is the recipient ?",{ reply_markup: { keyboard: conversatioNames } - }, function (err, ret) { - if (err) return console.error(err); - }) + }); }); }); }); - } else if (message.text == "/cancel") { - reset(); - bot.sendMessage({ - chat_id: message.chat.id, - text: "Command canceled.", + + }); + + bot.onText(/\/cancel/, (msg, match) => { + const chatId = msg.chat.id; + if (!doAuth(msg)) return; + reset(); + bot.sendMessage( + msg.chat.id, + "Command canceled.",{ reply_markup: { hide_keyboard: true } - }, - function (err, ret) { - if (err) return console.error(err); }); - } else if (currentThreadId != undefined) { - if (message.photo != undefined) { - bot.getFile({ - file_id: message.photo[message.photo.length - 1].file_id, - dir: config.dir - }, function callback(err, arr) { - api.sendMessage({attachment: fs.createReadStream(arr.destination)}, currentThreadId, function (err, api) { - if (err) return console.error(err); - fs.unlink(arr.destination, function (err) { - if (err) throw err; - }); - }); + }); + + bot.onText(/\/start/, (msg, match) => { + const chatId = msg.chat.id; + if (!doAuth(msg)) return; + + bot.sendMessage(msg.chat.id, + getUsage(),{ + disable_web_page_preview: true }); + }); + + + + bot.on('message', (msg) => { + const chatId = msg.chat.id; + if (!doAuth(msg)) return; + if (msg.text != undefined && msg.text[0] == '/') return; + if (!!msg.reply_to_message + && !!chat.get(msg.reply_to_message.message_id)) { //it is a reply message from FB + + api.sendMessage(msg.text, + chat.get(msg.reply_to_message.message_id), function (err, messageInfo) { + if (err) return console.error(err); + }); + } + + if (currentThreadId != undefined) { + if (msg.photo != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.photo[msg.photo.length - 1].file_id, msg.caption); + } else if (msg.sticker != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.sticker.file_id); + } else if (msg.audio != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.audio.file_id, msg.caption); + } else if (msg.voice != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.voice.file_id, msg.caption); + } else if (msg.video != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.video.file_id, msg.caption); + } else if (msg.video_note != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.video_note.file_id); + } else if (msg.document != undefined) { + sendAttachmentToFacebook(currentThreadId, msg.chat.id, msg.document.file_id, msg.caption); } else { - api.sendMessage(message.text, - currentThreadId, function (err, api) { + api.sendMessage(msg.text, + currentThreadId, function (err, messageInfo) { if (err) return console.error(err); }); } - } else if (threadListTmp != undefined) { //Check if owner have send a good recipient name + } else if (threadListTmp != undefined) { //Check if owner have send a good recipient name currentThreadId = undefined; for (var x = 0; x < threadListTmp.length; x++) { - if (threadListTmp[x].name == message.text) + if (threadListTmp[x].name == msg.text) currentThreadId = threadListTmp[x].threadID; } if (currentThreadId != undefined) - bot.sendMessage({ - chat_id: message.chat.id, - text: "What is the message for him ?", + bot.sendMessage( + msg.chat.id, + "What is the message for him ?",{ reply_markup: { hide_keyboard: true } - }, - function (err, ret) { - if (err) return console.error(err); }); else - bot.sendMessage({ - chat_id: message.chat.id, - text: "I do not know him, Please give me a correct name or /cancel." - }, - function (err, ret) { - if (err) return console.error(err); - }); - } else { - bot.sendMessage({ - chat_id: message.chat.id, - text: getUsage(), - disable_web_page_preview: true - }, - function (err, ret) { - if (err) return console.error(err); - }); - } - } - } - }).start(); + bot.sendMessage( + msg.chat.id, + "I do not know him, Please give me a correct name or /cancel." + ); + } + + }); +} +if (!fs.existsSync(botWorkingDir)) { + fs.mkdirSync(botWorkingDir); +} +if (!fs.existsSync(botWorkingDir + "/temp")){ + fs.mkdirSync(botWorkingDir + "/temp"); +} +console.log("Data directory: " + botWorkingDir); +initListeners(); + + + +login({email: process.env.FACEBOOK_USERNAME, password: process.env.FACEBOOK_PASSWORD}, async function (err, lapi) { + if (err) return console.error(err); + + await retrieveFriendsFromFacebook(lapi); + api = lapi; //listen message from FB and forward to telegram if (!owner.chat_id) { console.error("No chat id found."); + fbReady = true; } else { - api.listen(function callback(err, message) { - if (err) { - console.error("Errors on facebook listening", err); - } - else if (message) { - // gets the fb user name given his id - const senderName = friends[message.senderID] || message.senderID; - - if (message.attachments.length > 0) { - sendAttachmentsToTelegram(bot, senderName, message); - } else { - sendTextMessageToTelegram(bot, senderName, message, message.body); - } - } else { - console.log("no message from facebook"); - } - - }); + initFBlistener(); } }); @@ -196,13 +252,12 @@ const sendTextMessageToTelegram = function (bot, senderName, message, text) { if (message.isGroup) { forwardmsg = message.threadID + ": " + forwardmsg; } - - bot.sendMessage({chat_id: owner.chat_id, text: forwardmsg}, function (err, res) { - if (err) return console.error(err); - - //save message id send and fb thread id for futur reply - chat[res.message_id] = message.threadID; - }) + console.log("Forwarding message to TG: "); + console.log(" - " + forwardmsg); + bot.sendMessage(owner.chat_id, forwardmsg).then(function(err, tgMessage) { + if(err) throw err; + chat.set(tgMessage.message_id, message.thread_id); + }); }; const sendAttachmentsToTelegram = function (bot, senderName, message) { @@ -221,7 +276,22 @@ const sendAttachmentsToTelegram = function (bot, senderName, message) { } } +const sendAttachmentToFacebook = function (fbThreadID, tgChatID, file_id, caption) { + //would be cool if this worked, can't bother to fix though + // api.sendMessage({body: caption, attachment: bot.getFileStream(file_id)}, fbThreadID, function (err, messageInfo) { + // if(err) throw err; + // }); + + return bot.downloadFile(file_id, botWorkingDir + "/temp").then( function(arr) { + api.sendMessage({body: caption, attachment: fs.createReadStream(arr)}, fbThreadID, function (err, messageInfo) { + fs.unlink(arr, function (err) { + if (err) throw err; + }); + }); + }) +} + function reset() { currentThreadId = undefined; threadListTmp = undefined; -} \ No newline at end of file +} diff --git a/lib/findThread.js b/lib/findThread.js index e5c7e18..15f810f 100644 --- a/lib/findThread.js +++ b/lib/findThread.js @@ -47,25 +47,20 @@ module.exports = { }, - createThreads : function(arr, ret, cb) { + createThreads : function(arr, cb) { var threadListTmp = new Array(); - var userIds = new Array(); - - for(var prop in ret) { - userIds[prop] = ret[prop].name; - } for (var i = 0; i < arr.length; i++) { if (!arr[i].name) { var conversatioName = ""; - for (var j = 0; j < arr[i].participants.length; j++) { - fbid = arr[i].participants[j].replace('fbid:',''); + for (var j = 0; j < arr[i].participantIDs.length; j++) { + fbid = arr[i].participantIDs[j]; + uname = arr[i].participants[j].name; - if (userIds[fbid]) { if (conversatioName) conversatioName += ","; - conversatioName += userIds[fbid]; - } + conversatioName += uname; + } threadListTmp.push({threadID: arr[i].threadID, name: conversatioName}); diff --git a/package.json b/package.json index 2b539e0..4cf5df6 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ }, "homepage": "https://github.com/Liryna/FacebookBot", "dependencies": { - "facebook-chat-api": "git+https://github.com/Schmavery/facebook-chat-api.git", - "node-telegram-bot": "^0.1.5" + "facebook-chat-api": "git+https://github.com/ravkr/facebook-chat-api.git", + "node-telegram-bot-api": "git+https://github.com/yagop/node-telegram-bot-api.git" }, "scripts": {} } diff --git a/start.sh b/start.sh deleted file mode 100755 index a21388a..0000000 --- a/start.sh +++ /dev/null @@ -1,3 +0,0 @@ -TELEGRAM_USER="your telegram login" -APP_TOKEN="the token of your bot that BotFather gave you" -node facebookbot.js