<html> <!-- The license of this page is Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0) --> <head> <title>Flukybot</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style type="text/css">body{margin:40px auto;max-width:650px;line-height:1.4;font-size:16px;color:#444;padding:0 10px}h1,h2,h3{font-family: sans-serif; line-height:1.2}</style> </head> <body> <h1>Run a Bot locally in your browser</h1> <p>This page will run a Telegram bot locally in your web browser. Just enter your bot token from <a href="https://telegram.me/botfather">BotFather</a> and press the Start button. Press the button again or reload the page to stop the bot.</p> <p>The source code of this bot is also <a href="https://github.com/nadam/flukybot">available on Github</a>. <br><br> <label for="token">Bot token</label><br> <input id="token" type="text" placeholder="Paste your bot token from @BotFather here" size=60 /><br><br> <button id="startStop" type="button" onclick="startBot()">Start</button> <p id="output"></p> <script> var output = document.getElementById("output"); var startStop = document.getElementById("startStop"); var running = false; var botUrl; var xhr; // XMLHttpRequest // Use token from the url query string if present var query = window.location.search; var token = query.replace("?token=", ''); document.getElementById("token").value = token; function startBot() { var token = document.getElementById("token").value; botUrl = "https://api.telegram.org/bot" + token + "/"; log("Bot started"); startStop.innerText = "Stop"; startStop.onclick = stopBot; running = true; getUpdates(); // Start long polling } function stopBot() { running = false; log("Bot stopped"); xhr.abort(); startStop.innerText = "Start"; startStop.onclick = startBot; } var nextUpdateId = 0; // Long polling of getUpdates function getUpdates() { call("getUpdates", { offset: nextUpdateId, limit: 100, timeout: 30 }, function(updates) { if (updates.length > 0) { for (var i=0; i<updates.length; ++i) { handleUpdate(updates[i]); } var lastUpdate = updates[updates.length-1]; nextUpdateId = lastUpdate.update_id + 1; } if (running) { getUpdates(); } else { log("Bot stopped"); } }, function(errorCode, errorText) { log(errorText); stopBot(); }, 35); } function handleUpdate(update) { if (update.message) { handleMessage(update.message); } else if (update.edited_message) { handleEditedMessage(update.edited_message); } else if (update.inline_query) { handleInlineQuery(update.inline_query); } else if (update.chosen_inline_result) { handleChosenInlineResult(update.chosen_inline_result); } else if (update.callback_query) { handleCallbackQuery(update.callback_query); } } function handleMessage(message) { if (message.text) { log(message.from.id + ": " + message.text); if (message.text == "/help") { call("sendMessage", { chat_id: message.chat.id, text: "I'm a bot temporarily running locally in a browser. You can use the following commands:\n" + "/help - Show instructions\n" + "/keyboard - Show a simple keyboard\n" + "/hidekeyboard - Hide the keyboard\n" + "/inlinekeyboard - Show an inline keyboard" }); } else if (message.text == "/keyboard") { call("sendMessage", { chat_id: message.chat.id, text: "Please select a command", reply_markup: { keyboard: [ [{text: "Left"}, {text: "Right"}], [{text: "/hidekeyboard"}] ] } }); } else if (message.text == "/hidekeyboard") { call("sendMessage", { chat_id: message.chat.id, text: "Keyboard removed", reply_markup: { hide_keyboard: true } }); } else if (message.text == "/inlinekeyboard") { call("sendMessage", { chat_id: message.chat.id, text: "This message has an inline keyboard", reply_markup: { inline_keyboard: [ [{text: "Google", url: "https://google.com"}], [{text: "Hide", callback_data: "HIDE"}] ] } }); } } else { log(message.from.id + ": " + toJson(message)); } } function handleEditedMessage(message) { if (message.text) { log(message.from.id + " (edit): " + message.text); } else { log(message.from.id + " (edit): " + toJson(message)); } } function handleInlineQuery(inlineQuery) { log(toJson(inlineQuery)); if (!inlineQuery.query) { return; // No query text yet } call("answerInlineQuery", { inline_query_id: inlineQuery.id, results: [ { type: "article", id: "B", title: "Bold", input_message_content: { message_text: "<b>" + inlineQuery.query + "</b>", parse_mode: "HTML" }, description: "*" + inlineQuery.query + "*" }, { type: "article", id: "I", title: "Italic", input_message_content: { message_text: "<i>" + inlineQuery.query + "</i>", parse_mode: "HTML" }, description: "_" + inlineQuery.query + "_" } ] }); } function handleChosenInlineResult(inlineResult) { log(toJson(inlineResult)); } function handleCallbackQuery(query) { log(toJson(query)); if (query.data == "HIDE") { call("editMessageText", { chat_id: query.message.chat.id, message_id: query.message.message_id, text: "Keyboard hidden" }); } } function call(method, params, onResponse, onError, timeout) { xhr = new XMLHttpRequest(); xhr.open("POST", botUrl + method); xhr.setRequestHeader("Content-type", "application/json"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.responseText) { var response = JSON.parse(xhr.responseText); if (response.result) { if (onResponse) { onResponse(response.result); } } else if (onError) { onError(response.error_code, response.description); } else { log(method + ": " + response.description); } } } xhr.timeout = timeout ? timeout * 1000 : 15000; xhr.ontimeout = function() { if (onError) { onError(-1, "Timeout"); } else { log(method + ": Timeout"); } }; xhr.send(JSON.stringify(params)); } function log(message) { output.innerHTML = "<pre>" +new Date().toLocaleTimeString() + "\n" + message + "</pre>" + output.innerHTML; } function toJson(object) { return JSON.stringify(object, undefined, 2); } </script> </body> </html>