Compare commits
17 Commits
31bd289f32
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 149ab033b0 | |||
| f3b74b65ed | |||
| 17eb4e8bdd | |||
| 7bdebb7fd3 | |||
| bb9a9f7a9b | |||
| 0434bf5854 | |||
| 0238610cd1 | |||
| c4afd9139e | |||
| a9ed7aa159 | |||
| 489dccaa4e | |||
| 47592d5c44 | |||
| 2d377081b6 | |||
| a5ed267b32 | |||
| e075c24306 | |||
| 7639027684 | |||
| 1632bbfbe2 | |||
| a982ee0525 |
21
README.md
21
README.md
@@ -1,2 +1,23 @@
|
|||||||
# minetest-telegram-bridge
|
# minetest-telegram-bridge
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
+ Install `python3`, `flask`, `python-telegram-bot`
|
||||||
|
+ `cd`
|
||||||
|
+ `git clone https://git.webionite.com/ceda_ei/minetest-telegram-bridge`
|
||||||
|
+ `ln -s ~/minetest-telegram-bridge/chat_mod ~/.minetest/mods/chat_mod`
|
||||||
|
+ Add mod to `secure.http_mods`.
|
||||||
|
+ Add this line if `secure.http_mods` doesn't exist. `secure.http_mods = chat_mod`
|
||||||
|
+ Enable the mod in `world.mt`
|
||||||
|
+ `cd minetest-telegram-bridge/bot`
|
||||||
|
+ Copy `sample.config.py` to `config.py` and edit.
|
||||||
|
+ `python3 bot.py &`
|
||||||
|
+ `export FLASK_APP=server.py`
|
||||||
|
+ `export FLASK_ENV=production`
|
||||||
|
+ `flask run -p 9876`
|
||||||
|
+ Start the minetest server via `minetest [params] |& python3 pipe_in.py`
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
To use a different port, change the respective config in `config.py` and add `chat_server_port = PORT` in `minecraft.conf` and run `flask run -p PORT` instead of the last step.
|
||||||
|
|||||||
99
bot/bot.py
99
bot/bot.py
@@ -3,25 +3,104 @@
|
|||||||
import config
|
import config
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from telegram.ext import Updater, MessageHandler, Filters
|
import re
|
||||||
|
from emoji import demojize
|
||||||
|
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
|
||||||
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - \
|
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - \
|
||||||
%(message)s', level=logging.INFO)
|
%(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
def get_text_or_type(msg, bot, truncate=False):
|
||||||
|
message = ""
|
||||||
|
|
||||||
|
# Set message contents
|
||||||
|
if msg.text:
|
||||||
|
if msg.from_user.username == bot.username and re.match('<.*?>(.*)',
|
||||||
|
msg.text):
|
||||||
|
x = re.compile('(<.*?>)(.*)')
|
||||||
|
y = x.search(msg.text)
|
||||||
|
z = y.group(2)
|
||||||
|
message += (z if len(z) <= 20 or not truncate else z[0:19] + "...")
|
||||||
|
else:
|
||||||
|
message += (msg.text if len(msg.text) <= 20 or not truncate else
|
||||||
|
msg.text[0:19] + "...")
|
||||||
|
elif msg.audio:
|
||||||
|
message += "[Audio]"
|
||||||
|
elif msg.document:
|
||||||
|
message += "[Document]"
|
||||||
|
elif msg.animation:
|
||||||
|
message += "[GIF]"
|
||||||
|
elif msg.game:
|
||||||
|
message += "[Game]"
|
||||||
|
elif msg.photo:
|
||||||
|
message += "[Photo]"
|
||||||
|
elif msg.sticker:
|
||||||
|
message += "[Sticker]"
|
||||||
|
elif msg.video:
|
||||||
|
message += "[Video]"
|
||||||
|
elif msg.voice:
|
||||||
|
message += "[Voice Note]"
|
||||||
|
elif msg.video_note:
|
||||||
|
message += "[Video Note]"
|
||||||
|
elif msg.contact:
|
||||||
|
message += "[Contact]"
|
||||||
|
elif msg.location:
|
||||||
|
message += "[Location]"
|
||||||
|
elif msg.venue:
|
||||||
|
message += "[Venue]"
|
||||||
|
else:
|
||||||
|
message += "[Unknown type]"
|
||||||
|
|
||||||
|
# If caption exists
|
||||||
|
if msg.caption:
|
||||||
|
message += (msg.caption if len(msg.caption) <= 20 or not truncate else
|
||||||
|
msg.caption[0:19] + "...")
|
||||||
|
|
||||||
|
# Set sender
|
||||||
|
return_message = ""
|
||||||
|
for i in message.strip().split("\n"):
|
||||||
|
if msg.from_user.username != bot.username or not re.match('<.*?>(.*)',
|
||||||
|
msg.text):
|
||||||
|
if msg.from_user.username:
|
||||||
|
return_message += f"@{msg.from_user.username}: "
|
||||||
|
else:
|
||||||
|
return_message += f"{msg.from_user.first_name}: "
|
||||||
|
else:
|
||||||
|
x = re.compile('(<.*?>)(.*)')
|
||||||
|
y = x.search(msg.text)
|
||||||
|
return_message = y.group(1) + ": " + i + "\n"
|
||||||
|
# Set the replied to message's contents
|
||||||
|
if msg.reply_to_message:
|
||||||
|
return_message += ("[> " +
|
||||||
|
get_text_or_type(msg.reply_to_message, bot,
|
||||||
|
True).split("\n")[0] +
|
||||||
|
f"] ")
|
||||||
|
return_message += i + "\n"
|
||||||
|
|
||||||
|
return return_message.strip()
|
||||||
|
|
||||||
|
|
||||||
def message_handling(bot, update):
|
def message_handling(bot, update):
|
||||||
print("in here")
|
|
||||||
if update.message.chat.id in config.groups:
|
if update.message.chat.id in config.groups:
|
||||||
print("in here")
|
message = get_text_or_type(update.message, bot)
|
||||||
for i in update.message.text.split("\n"):
|
params = {"message": demojize(message)}
|
||||||
params = {"message": (f"TG - {update.message.from_user.first_name}"
|
requests.post("http://localhost:" + str(config.port) + "/post",
|
||||||
f": {i}")}
|
data=params)
|
||||||
requests.post("http://localhost:" + str(config.port) + "/post",
|
|
||||||
data=params)
|
|
||||||
print(params)
|
def direct_cmd(bot, update, text):
|
||||||
|
if update.message.chat.id in config.groups:
|
||||||
|
params = {"message": text}
|
||||||
|
requests.post("http://localhost:" + str(config.port) + "/post",
|
||||||
|
data=params)
|
||||||
|
|
||||||
|
|
||||||
updater = Updater(token=config.api_key)
|
updater = Updater(token=config.api_key)
|
||||||
dispatcher = updater.dispatcher
|
dispatcher = updater.dispatcher
|
||||||
dispatcher.add_handler(MessageHandler(Filters.text, message_handling))
|
dispatcher.add_handler(CommandHandler('list', lambda x, y: direct_cmd(x, y,
|
||||||
|
"list")))
|
||||||
|
dispatcher.add_handler(CommandHandler('time', lambda x, y: direct_cmd(x, y,
|
||||||
|
"time")))
|
||||||
|
dispatcher.add_handler(MessageHandler(Filters.all, message_handling))
|
||||||
updater.start_polling()
|
updater.start_polling()
|
||||||
|
|||||||
7
bot/pipe_in.py
Executable file
7
bot/pipe_in.py
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
for line in sys.stdin:
|
||||||
|
if not re.match(".* Mod performs HTTP request with URL ", line):
|
||||||
|
print(line, end="")
|
||||||
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
from flask import Flask, request
|
from flask import Flask, request
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import config
|
||||||
|
import telegram
|
||||||
|
import re
|
||||||
|
from emoji import emojize
|
||||||
|
|
||||||
|
|
||||||
|
def escape_html(message):
|
||||||
|
return re.sub("<", "<",
|
||||||
|
re.sub(">", "&rt;",
|
||||||
|
re.sub("&", "&", message)))
|
||||||
|
|
||||||
|
|
||||||
def get(db):
|
def get(db):
|
||||||
@@ -25,8 +35,23 @@ def post(db):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def send(bot, code):
|
||||||
|
message = request.form["message"]
|
||||||
|
if code:
|
||||||
|
message = escape_html(message)
|
||||||
|
message = "<code>" + message + "</code>"
|
||||||
|
for i in config.groups:
|
||||||
|
bot.send_message(chat_id=i, text=emojize(message),
|
||||||
|
parse_mode="HTML")
|
||||||
|
else:
|
||||||
|
for i in config.groups:
|
||||||
|
bot.send_message(chat_id=i, text=emojize(message))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
db = sqlite3.connect(":memory:", check_same_thread=False)
|
db = sqlite3.connect(":memory:", check_same_thread=False)
|
||||||
|
bot = telegram.Bot(token=config.api_key)
|
||||||
|
|
||||||
# Set up tables
|
# Set up tables
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
@@ -35,3 +60,5 @@ with open('schema.sql') as fp:
|
|||||||
|
|
||||||
app.add_url_rule('/get', 'get', lambda: get(db))
|
app.add_url_rule('/get', 'get', lambda: get(db))
|
||||||
app.add_url_rule('/post', 'post', lambda: post(db), methods=["POST"])
|
app.add_url_rule('/post', 'post', lambda: post(db), methods=["POST"])
|
||||||
|
app.add_url_rule('/send', 'send', lambda: send(bot, False), methods=["POST"])
|
||||||
|
app.add_url_rule('/sendCode', 'sc', lambda: send(bot, True), methods=["POST"])
|
||||||
|
|||||||
@@ -1,21 +1,72 @@
|
|||||||
|
local http_api = minetest.request_http_api()
|
||||||
|
|
||||||
|
function tablelength(T)
|
||||||
|
local count = 0
|
||||||
|
for _ in pairs(T) do count = count + 1 end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
function send_messages(res)
|
function send_messages(res)
|
||||||
for message in string.gmatch(res["data"], "[^\n]+") do
|
for message in string.gmatch(res["data"], "[^\n]+") do
|
||||||
minetest.chat_send_all(message)
|
if message == "list" then
|
||||||
|
local x = minetest.get_connected_players()
|
||||||
|
local text = "List of Players ("
|
||||||
|
text = text .. tostring(tablelength(x)) .. "/"
|
||||||
|
text = text .. tostring(minetest.settings:get("max_users")) .. "):"
|
||||||
|
for j, i in ipairs(x) do
|
||||||
|
text = text .. "\n" .. i.get_player_name(i)
|
||||||
|
end
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/sendCode",
|
||||||
|
post_data = {message = text}})
|
||||||
|
elseif message == "time" then
|
||||||
|
local x = minetest.get_timeofday()
|
||||||
|
local text = string.format("%02d:%02d", math.floor(x*24), math.floor((x*24*60) % 60))
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/sendCode",
|
||||||
|
post_data = {message = text}})
|
||||||
|
else
|
||||||
|
minetest.chat_send_all(message)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function main(http_api)
|
function main()
|
||||||
port = minetest.settings:get("chat_server_port")
|
port = minetest.settings:get("chat_server_port")
|
||||||
if port == nil then
|
if port == nil then
|
||||||
port = "9876"
|
port = "9876"
|
||||||
end
|
end
|
||||||
http_api.fetch({url = "http://localhost:" .. port .. "/get"}, send_messages)
|
http_api.fetch({url = "http://localhost:" .. port .. "/get"}, send_messages)
|
||||||
minetest.after(0.5, main, http_api)
|
minetest.after(0.5, main)
|
||||||
|
end
|
||||||
|
|
||||||
|
function dead(player)
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/sendCode",
|
||||||
|
post_data = {message = player.get_player_name(player) ..
|
||||||
|
" died."}})
|
||||||
|
end
|
||||||
|
|
||||||
|
function join(player)
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/sendCode",
|
||||||
|
post_data = {message = player.get_player_name(player) ..
|
||||||
|
" joined the server."}})
|
||||||
|
end
|
||||||
|
|
||||||
|
function left(player)
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/sendCode",
|
||||||
|
post_data = {message = player.get_player_name(player) ..
|
||||||
|
" left the server."}})
|
||||||
|
end
|
||||||
|
|
||||||
|
function chat(name, message)
|
||||||
|
http_api.fetch_async({url = "http://localhost:" .. port .. "/send",
|
||||||
|
post_data = {message = "<" .. name .. "> " .. message}})
|
||||||
end
|
end
|
||||||
|
|
||||||
local http_api = minetest.request_http_api()
|
|
||||||
if http_api == nil then
|
if http_api == nil then
|
||||||
minetest.log("error", "Chat Mod is not in secure.http_mods or secure.trusted_mods. Exiting.")
|
minetest.log("error", "Chat Mod is not in secure.http_mods or secure.trusted_mods. Exiting.")
|
||||||
else
|
else
|
||||||
main(http_api)
|
main()
|
||||||
end
|
end
|
||||||
|
minetest.register_on_dieplayer(dead)
|
||||||
|
minetest.register_on_joinplayer(join)
|
||||||
|
minetest.register_on_leaveplayer(left)
|
||||||
|
minetest.register_on_chat_message(chat)
|
||||||
|
|||||||
Reference in New Issue
Block a user