Committe aktuellen Status.

NEU:
- Twitter-Plugin (ohne Markdown bisher)
- Get- Set-Plugins
- 9GAG
- Adfly
- Redis-Integration
- Google Search
- Google Images (modifiziert, mit Blacklist, bisher ohne Caching)
- Einige Plugins lokalisiert

Das ist momentan noch alles WIP, das meiste ist einfach bloß copy&paste vom proprietären
Brawlbot v1.
This commit is contained in:
Andreas Bielawski 2016-06-11 14:46:41 +02:00
parent 31a8e220ac
commit a4d7c40ad9
58 changed files with 1039 additions and 248 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
otouto/plugins/mokubot*
config.lua
*.db
tg

0
LICENSE Executable file → Normal file
View File

2
README.md Executable file → Normal file
View File

@ -1,4 +1,4 @@
# otouto
# Brawlbot, auf Basis von otouto
The plugin-wielding, multipurpose Telegram bot.
[Public Bot](http://telegram.me/mokubot) | [Official Channel](http://telegram.me/otouto) | [Development Group](http://telegram.me/BotDevelopment)

56
config.lua → config.lua.example Executable file → Normal file
View File

@ -3,9 +3,9 @@ return {
-- Your authorization token from the botfather.
bot_api_key = '',
-- Your Telegram ID.
admin = 00000000,
admin = 1337,
-- Two-letter language code.
lang = 'en',
lang = 'de',
-- The channel, group, or user to send error reports to.
-- If this is not set, errors will be printed to the console.
log_chat = nil,
@ -14,42 +14,22 @@ return {
cli_port = 4567,
-- The block of text returned by /start.
about_text = [[
I am otouto, the plugin-wielding, multipurpose Telegram bot.
Dies ist die BETA-Version von Brawlbot v2.
Send /help to get started.
Sende /hilfe, um zu starten
]],
-- The symbol that starts a command. Usually noted as '/' in documentation.
cmd_pat = '/',
-- https://datamarket.azure.com/dataset/bing/search
bing_api_key = '',
-- http://console.developers.google.com
google_api_key = '',
-- https://cse.google.com/cse
google_cse_key = '',
-- http://openweathermap.org/appid
owm_api_key = '',
-- http://last.fm/api
lastfm_api_key = '',
-- http://api.biblia.com
biblia_api_key = '',
-- http://thecatapi.com/docs.html
thecatapi_key = '',
-- http://api.nasa.gov
nasa_api_key = '',
-- http://tech.yandex.com/keys/get
yandex_key = '',
-- http://developer.simsimi.com/signUp
simsimi_key = '',
simsimi_trial = true,
errors = { -- Generic error messages used in various plugins.
connection = 'Connection error.',
results = 'No results found.',
argument = 'Invalid argument.',
syntax = 'Invalid syntax.',
chatter_connection = 'I don\'t feel like talking right now.',
chatter_response = 'I don\'t know what to say to that.'
connection = 'Verbindungsfehler.',
quotaexceeded = 'API-Quota aufgebraucht.',
results = 'Keine Ergebnisse gefunden.',
sudo = 'Du bist kein Superuser. Dieser Vorfall wird gemeldet!',
argument = 'Invalides Argument.',
syntax = 'Invalide Syntax.',
chatter_connection = 'Ich möchte gerade nicht reden',
chatter_response = 'Ich weiß nicht, was ich darauf antworten soll.'
},
plugins = { -- To enable a plugin, add its name to the list.
@ -60,6 +40,9 @@ Send /help to get started.
'whoami',
'nick',
'echo',
'imgblacklist',
'gImages',
'gSearch',
'gMaps',
'wikipedia',
'hackernews',
@ -67,7 +50,6 @@ Send /help to get started.
'calc',
'urbandictionary',
'time',
'eightball',
'dice',
'reddit',
'xkcd',
@ -75,8 +57,14 @@ Send /help to get started.
'commit',
'pun',
'currency',
'cats',
'shout',
'set',
'get',
'patterns',
'9gag',
'shell',
'adfly',
'twitter',
-- Put new plugins above this line.
'help',
'greetings'

0
launch.sh Executable file → Normal file
View File

0
otouto/bindings.lua Executable file → Normal file
View File

56
otouto/bot.lua Executable file → Normal file
View File

@ -3,13 +3,16 @@ local bot = {}
-- Requires are moved to init to allow for reloads.
local bindings -- Load Telegram bindings.
local utilities -- Load miscellaneous and cross-plugin functions.
local redis = (loadfile "./otouto/redis.lua")()
bot.version = '3.9'
bot.version = '2'
function bot:init(config) -- The function run when the bot is started or reloaded.
bindings = require('otouto.bindings')
utilities = require('otouto.utilities')
redis = (loadfile "./otouto/redis.lua")()
cred_data = load_cred()
assert(
config.bot_api_key and config.bot_api_key ~= '',
@ -127,4 +130,55 @@ function bot:run(config)
print('Halted.')
end
function load_cred()
if redis:exists("telegram:credentials") == false then
-- If credentials hash doesnt exists
print ("Created new credentials hash: telegram:credentials")
create_cred()
end
return redis:hgetall("telegram:credentials")
end
-- create credentials hash with redis
function create_cred()
cred = {
bitly_access_token = "",
cloudinary_apikey = "",
cloudinary_api_secret = "",
cloudinary_public_id = "",
derpibooru_apikey = "",
fb_access_token = "",
flickr_apikey = "",
ftp_site = "",
ftp_username = "",
ftp_password = "",
gender_apikey = "",
golem_apikey = "",
google_apikey = "",
google_cse_id = "",
gitlab_private_token = "",
gitlab_project_id = "",
instagram_access_token = "",
lyricsnmusic_apikey = "",
mal_username = "",
mal_pw = "",
neutrino_userid = "",
neutrino_apikey = "",
owm_apikey = "",
page2images_restkey = "",
soundcloud_client_id = "",
tw_consumer_key = "",
tw_consumer_secret = "",
tw_access_token = "",
tw_access_token_secret = "",
x_mashape_key = "",
yandex_translate_apikey = "",
yandex_rich_content_apikey = "",
yourls_site_url = "",
yourls_signature_token = ""
}
redis:hmset("telegram:credentials", cred)
print ('saved credentials into reds hash telegram:credentials')
end
return bot

100
otouto/mimetype.lua Normal file
View File

@ -0,0 +1,100 @@
-- Thanks to https://github.com/catwell/lua-toolbox/blob/master/mime.types
do
local mimetype = {}
-- TODO: Add more?
local types = {
["text/html"] = "html",
["text/css"] = "css",
["text/xml"] = "xml",
["image/gif"] = "gif",
["image/jpeg"] = "jpg",
["application/x-javascript"] = "js",
["application/atom+xml"] = "atom",
["application/rss+xml"] = "rss",
["text/mathml"] = "mml",
["text/plain"] = "txt",
["text/vnd.sun.j2me.app-descriptor"] = "jad",
["text/vnd.wap.wml"] = "wml",
["text/x-component"] = "htc",
["image/png"] = "png",
["image/tiff"] = "tiff",
["image/vnd.wap.wbmp"] = "wbmp",
["image/x-icon"] = "ico",
["image/x-jng"] = "jng",
["image/x-ms-bmp"] = "bmp",
["image/svg+xml"] = "svg",
["application/java-archive"] = "jar",
["application/mac-binhex40"] = "hqx",
["application/msword"] = "doc",
["application/pdf"] = "pdf",
["application/postscript"] = "ps",
["application/rtf"] = "rtf",
["application/vnd.android.package-archive"] = "apk",
["application/vnd.ms-excel"] = "xls",
["application/vnd.ms-powerpoint"] = "ppt",
["application/vnd.wap.wmlc"] = "wmlc",
["application/vnd.google-earth.kml+xml"] = "kml",
["application/vnd.google-earth.kmz"] = "kmz",
["application/x-7z-compressed"] = "7z",
["application/x-cocoa"] = "cco",
["application/x-java-archive-diff"] = "jardiff",
["application/x-java-jnlp-file"] = "jnlp",
["application/x-makeself"] = "run",
["application/x-perl"] = "pl",
["application/x-pilot"] = "prc",
["application/x-rar-compressed"] = "rar",
["application/x-redhat-package-manager"] = "rpm",
["application/x-sea"] = "sea",
["application/x-shockwave-flash"] = "swf",
["application/x-stuffit"] = "sit",
["application/x-tcl"] = "tcl",
["application/x-x509-ca-cert"] = "crt",
["application/x-xpinstall"] = "xpi",
["application/xhtml+xml"] = "xhtml",
["application/zip"] = "zip",
["application/octet-stream"] = "bin",
["audio/midi"] = "mid",
["audio/mpeg"] = "mp3",
["audio/ogg"] = "ogg",
["audio/x-m4a"] = "m4a",
["audio/x-realaudio"] = "ra",
["video/3gpp"] = "3gpp",
["video/mp4"] = "mp4",
["video/mpeg"] = "mpeg",
["video/quicktime"] = "mov",
["video/x-flv"] = "flv",
["video/x-m4v"] = "m4v",
["video/x-mng"] = "mng",
["video/x-ms-asf"] = "asf",
["video/x-ms-wmv"] = "wmv",
["video/x-msvideo"] = "avi"
}
-- Returns the common file extension from a content-type
function mimetype.get_mime_extension(content_type)
return types[content_type]
end
-- Returns the mimetype and subtype
function mimetype.get_content_type(extension)
for k,v in pairs(types) do
if v == extension then
return k
end
end
end
-- Returns the mimetype without the subtype
function mimetype.get_content_type_no_sub(extension)
for k,v in pairs(types) do
if v == extension then
-- Before /
return k:match('([%w-]+)/')
end
end
end
return mimetype
end

41
otouto/plugins/9gag.lua Normal file
View File

@ -0,0 +1,41 @@
local ninegag = {}
local HTTP = require('socket.http')
local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
local bindings = require('otouto.bindings')
ninegag.command = '9gag'
function ninegag:init(config)
ninegag.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('9gag', true):t('9fag', true).table
ninegag.doc = [[*
]]..config.cmd_pat..[[9gag*: Gibt ein zufälliges Bild von den momentan populärsten 9GAG-Posts aus]]
end
function ninegag:get_9GAG()
local url = "http://api-9gag.herokuapp.com/"
local b,c = HTTP.request(url)
if c ~= 200 then return nil end
local gag = JSON.decode(b)
-- random max json table size
local i = math.random(#gag) local link_image = gag[i].src
local title = gag[i].title
return link_image, title, post_url
end
function ninegag:action(msg, config)
local url, title = ninegag:get_9GAG()
if not url then
utilities.send_reply(self, msg, config.errors.connection)
return
end
local file = download_to_file(url)
bindings.sendPhoto(self, {chat_id = msg.chat.id, caption = title}, {photo = file} )
os.remove(file)
print("Deleted: "..file)
end
return ninegag

4
otouto/plugins/about.lua Executable file → Normal file
View File

@ -4,7 +4,7 @@ local bot = require('otouto.bot')
local utilities = require('otouto.utilities')
about.command = 'about'
about.doc = '`Returns information about the bot.`'
about.doc = '`Sendet Informationen über den Bot.`'
about.triggers = {
''
@ -16,7 +16,7 @@ function about:action(msg, config)
-- other plugins.
if msg.forward_from then return end
local output = config.about_text .. '\nBased on otouto v'..bot.version..' by topkecleon.'
local output = config.about_text .. '\nBrawlbot v2, basierend auf Otouto v'..bot.version..' von topkecleon.'
if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id)
or msg.text_lower:match('^'..config.cmd_pat..'about')

49
otouto/plugins/adfly.lua Normal file
View File

@ -0,0 +1,49 @@
local adfly = {}
local utilities = require('otouto.utilities')
local HTTPS = require('ssl.https')
local redis = (loadfile "./otouto/redis.lua")()
function adfly:init(config)
adfly.triggers = {
'adf.ly/([A-Za-z0-9-_-]+)'
}
adfly.doc = [[*adf.ly-Link*: Postet vollen Link]]
end
function adfly:expand_adfly_link(adfly_code)
local BASE_URL = 'https://andibi.tk/dl/adfly.php'
local url = BASE_URL..'/?url=http://adf.ly/'..adfly_code
local res,code = HTTPS.request(url)
if code ~= 200 then return nil end
if res == 'Fehler: Keine Adf.ly-URL gefunden!' then return 'NOTFOUND' end
cache_data('adfly', adfly_code, res, 31536000, 'key')
return res
end
function adfly:action(msg)
local input = msg.text
if not input:match('adf.ly/([A-Za-z0-9-_-]+)') then
return
end
local adfly_code = input:match('adf.ly/([A-Za-z0-9-_-]+)')
local hash = 'telegram:cache:adfly:'..adfly_code
if redis:exists(hash) == false then
local expanded_url = adfly:expand_adfly_link(adfly_code)
if not expanded_url then
utilities.send_reply(self, msg, config.errors.connection)
return
end
if expanded_url == 'NOTFOUND' then
utilities.send_reply(self, msg, 'Fehler: Keine Adf.ly-URL gefunden!')
return
end
utilities.send_reply(self, msg, expanded_url)
else
local data = redis:get(hash)
utilities.send_reply(self, msg, data)
end
end
return adfly

0
otouto/plugins/apod.lua Executable file → Normal file
View File

0
otouto/plugins/bandersnatch.lua Executable file → Normal file
View File

0
otouto/plugins/bible.lua Executable file → Normal file
View File

0
otouto/plugins/blacklist.lua Executable file → Normal file
View File

0
otouto/plugins/calc.lua Executable file → Normal file
View File

0
otouto/plugins/cats.lua Executable file → Normal file
View File

0
otouto/plugins/chatter.lua Executable file → Normal file
View File

0
otouto/plugins/commit.lua Executable file → Normal file
View File

0
otouto/plugins/currency.lua Executable file → Normal file
View File

0
otouto/plugins/dice.lua Executable file → Normal file
View File

0
otouto/plugins/echo.lua Executable file → Normal file
View File

0
otouto/plugins/eightball.lua Executable file → Normal file
View File

0
otouto/plugins/fortune.lua Executable file → Normal file
View File

86
otouto/plugins/gImages.lua Executable file → Normal file
View File

@ -7,72 +7,70 @@ local HTTPS = require('ssl.https')
local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
local bindings = require('otouto.bindings')
function gImages:init(config)
if not config.google_api_key then
print('Missing config value: google_api_key.')
if not cred_data.google_apikey then
print('Missing config value: google_apikey.')
print('gImages.lua will not be enabled.')
return
elseif not config.google_cse_key then
print('Missing config value: google_cse_key.')
elseif not cred_data.google_cse_id then
print('Missing config value: google_cse_id.')
print('gImages.lua will not be enabled.')
return
end
gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('image', true):t('i', true):t('insfw', true).table
gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('img', true):t('i', true):t('insfw', true).table
gImages.doc = [[```
]]..config.cmd_pat..[[image <query>
Returns a randomized top result from Google Images. Safe search is enabled by default; use "]]..config.cmd_pat..[[insfw" to disable it. NSFW results will not display an image preview.
]]..config.cmd_pat..[[img <Suchbegriff>
Sucht Bild mit Google und versendet es (SafeSearch aktiv)
Alias: ]]..config.cmd_pat..[[i
```]]
end
gImages.command = 'image <query>'
gImages.command = 'img <Suchbegriff>'
function gImages:action(msg, config)
local input = utilities.input(msg.text)
if not input then
if msg.reply_to_message and msg.reply_to_message.text then
input = msg.reply_to_message.text
else
utilities.send_message(self, msg.chat.id, gImages.doc, true, msg.message_id, true)
return
end
local input = utilities.input(msg.text)
if not input then
if msg.reply_to_message and msg.reply_to_message.text then
input = msg.reply_to_message.text
else
utilities.send_message(self, msg.chat.id, gImages.doc, true, msg.message_id, true)
return
end
end
local url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. config.google_api_key .. '&cx=' .. config.google_cse_key
print ('Checking if search contains blacklisted word: '..input)
if is_blacklisted(input) then
utilities.send_reply(self, msg, 'Vergiss es! ._.')
return
end
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
url = url .. '&safe=high'
end
local apikey = cred_data.google_apikey
local cseid = cred_data.google_cse_id
local BASE_URL = 'https://www.googleapis.com/customsearch/v1'
local url = BASE_URL..'/?searchType=image&alt=json&num=10&key='..apikey..'&cx='..cseid..'&safe=high'..'&q=' .. URL.escape(input)
local jstr, res = HTTPS.request(url)
url = url .. '&q=' .. URL.escape(input)
if res ~= 200 then
utilities.send_reply(self, msg, config.errors.connection)
return
end
local jstr, res = HTTPS.request(url)
if res ~= 200 then
utilities.send_reply(self, msg, config.errors.connection)
return
end
local jdat = JSON.decode(jstr)
if jdat.searchInformation.totalResults == '0' then
utilities.send_reply(self, msg, config.errors.results)
return
end
local jdat = JSON.decode(jstr)
if jdat.searchInformation.totalResults == '0' then
utilities.send_reply(self, msg, config.errors.results)
return
end
local i = math.random(jdat.queries.request[1].count)
local img_url = jdat.items[i].link
local img_title = jdat.items[i].title
local output = '[' .. img_title .. '](' .. img_url .. ')'
if msg.text:match('nsfw') then
utilities.send_reply(self, '*NSFW*\n'..msg, output)
else
utilities.send_message(self, msg.chat.id, output, false, nil, true)
end
local i = math.random(jdat.queries.request[1].count)
local img_url = jdat.items[i].link
local file = download_to_file(img_url)
bindings.sendPhoto(self, {chat_id = msg.chat.id, caption = img_url}, {photo = file} )
os.remove(file)
print("Deleted: "..file)
end
return gImages

0
otouto/plugins/gMaps.lua Executable file → Normal file
View File

110
otouto/plugins/gSearch.lua Executable file → Normal file
View File

@ -10,71 +10,67 @@ gSearch.command = 'google <query>'
function gSearch:init(config)
gSearch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('g', true):t('google', true):t('gnsfw', true).table
gSearch.doc = [[```
]]..config.cmd_pat..[[google <query>
Returns four (if group) or eight (if private message) results from Google. Safe search is enabled by default, use "]]..config.cmd_pat..[[gnsfw" to disable it.
]]..config.cmd_pat..[[google <Suchbegriff>
Sendet Suchergebnisse von Google
Alias: ]]..config.cmd_pat..[[g
```]]
end
function gSearch:googlethat(query, config)
local BASE_URL = 'https://www.googleapis.com/customsearch/v1'
local apikey = config.google_api_key
local cseid = config.google_cse_key
local number = 5 -- Set number of results
local api = BASE_URL.."/?key="..apikey.."&cx="..cseid.."&gl=de&num="..number.."&safe=medium&fields=searchInformation%28formattedSearchTime,formattedTotalResults%29,items%28title,link,displayLink%29&"
local parameters = "q=".. (URL.escape(query) or "")
-- Do the request
local res, code = HTTPS.request(api..parameters)
if code == 403 then
utilities.send_reply(self, msg, config.errors.quotaexceeded)
return
end
if code ~= 200 then
utilities.send_reply(self, msg, config.errors.connection)
return
end
local data = JSON.decode(res)
if data.searchInformation.formattedTotalResults == "0" then return nil end
local results={}
for key,result in ipairs(data.items) do
table.insert(results, {
result.title,
result.link,
result.displayLink
})
end
local stats = data.searchInformation.formattedTotalResults..' Ergebnisse, gefunden in '..data.searchInformation.formattedSearchTime..' Sekunden'
return results, stats
end
function gSearch:stringlinks(results, stats)
local stringresults=""
for key,val in ipairs(results) do
stringresults=stringresults.."["..val[1].."]("..val[2]..") - `"..val[3].."`\n"
end
return stringresults..stats
end
function gSearch:action(msg, config)
local input = utilities.input(msg.text)
if not input then
if msg.reply_to_message and msg.reply_to_message.text then
input = msg.reply_to_message.text
else
utilities.send_message(self, msg.chat.id, gSearch.doc, true, msg.message_id, true)
return
end
end
local url = 'https://ajax.googleapis.com/ajax/services/search/web?v=1.0'
if msg.from.id == msg.chat.id then
url = url .. '&rsz=8'
local input = utilities.input(msg.text)
if not input then
if msg.reply_to_message and msg.reply_to_message.text then
input = msg.reply_to_message.text
else
url = url .. '&rsz=4'
utilities.send_message(self, msg.chat.id, gSearch.doc, true, msg.message_id, true)
return
end
end
if not string.match(msg.text, '^'..config.cmd_pat..'g[oogle]*nsfw') then
url = url .. '&safe=active'
end
url = url .. '&q=' .. URL.escape(input)
local jstr, res = HTTPS.request(url)
if res ~= 200 then
utilities.send_reply(self, msg, config.errors.connection)
return
end
local jdat = JSON.decode(jstr)
if not jdat.responseData then
utilities.send_reply(self, msg, config.errors.connection)
return
end
if not jdat.responseData.results[1] then
utilities.send_reply(self, msg, config.errors.results)
return
end
local output = '*Google results for* _' .. input .. '_ *:*\n'
for i,_ in ipairs(jdat.responseData.results) do
local title = jdat.responseData.results[i].titleNoFormatting:gsub('%[.+%]', ''):gsub('&amp;', '&')
--[[
if title:len() > 48 then
title = title:sub(1, 45) .. '...'
end
]]--
local u = jdat.responseData.results[i].unescapedUrl
if u:find('%)') then
output = output .. '' .. title .. '\n' .. u:gsub('_', '\\_') .. '\n'
else
output = output .. '• [' .. title .. '](' .. u .. ')\n'
end
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
local results, stats = gSearch:googlethat(input, config)
utilities.send_message(self, msg.chat.id, gSearch:stringlinks(results, stats), true, nil, true)
end

59
otouto/plugins/get.lua Normal file
View File

@ -0,0 +1,59 @@
local get = {}
local utilities = require('otouto.utilities')
local redis = (loadfile "./otouto/redis.lua")()
get.command = 'get <Variable>'
function get:init(config)
get.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('get', true).table
get.doc = [[*
]]..config.cmd_pat..[[get*: Gibt alle Variablen aus
*]]..config.cmd_pat..[[get* _<Variable>_: Gibt _Variable_ aus
Nutze `!set <Variable> <Wert>` zum Setzen von Variablen]]
end
function get:get_value(msg, var_name)
local hash = get_redis_hash(msg, 'variables')
if hash then
local value = redis:hget(hash, var_name)
if not value then
return'Nicht gefunden; benutze /get, um alle Variablen aufzulisten.'
else
return var_name..' = '..value
end
end
end
function get:list_variables(msg)
local hash = get_redis_hash(msg, 'variables')
print(hash)
if hash then
print('Getting variable from redis hash '..hash)
local names = redis:hkeys(hash)
local text = ''
for i=1, #names do
variables = get:get_value(msg, names[i])
text = text..variables.."\n"
end
if text == '' or text == nil then
return 'Keine Variablen vorhanden!'
else
return text
end
end
end
function get:action(msg)
local input = utilities.input(msg.text)
if input then
output = get:get_value(msg, input:match('(.+)'))
else
output = get:list_variables(msg)
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
end
return get

0
otouto/plugins/greetings.lua Executable file → Normal file
View File

0
otouto/plugins/hackernews.lua Executable file → Normal file
View File

0
otouto/plugins/hearthstone.lua Executable file → Normal file
View File

16
otouto/plugins/help.lua Executable file → Normal file
View File

@ -10,7 +10,7 @@ local help_text
function help:init(config)
local commandlist = {}
help_text = '*Available commands:*\n'..config.cmd_pat
help_text = '*Verfügbare Befehle:*\n'..config.cmd_pat
for _,plugin in ipairs(self.plugins) do
if plugin.command then
@ -19,14 +19,14 @@ function help:init(config)
end
end
table.insert(commandlist, 'help [command]')
table.insert(commandlist, 'hilfe [Plugin]')
table.sort(commandlist)
help_text = help_text .. table.concat(commandlist, '\n'..config.cmd_pat) .. '\nArguments: <required> [optional]'
help_text = help_text .. table.concat(commandlist, '\n'..config.cmd_pat) .. '\nParameter: <benötigt> [optional]'
help_text = help_text:gsub('%[', '\\[')
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hilfe', true):t('help', true).table
end
@ -39,22 +39,22 @@ function help:action(msg)
if not input then
local res = utilities.send_message(self, msg.from.id, help_text, true, nil, true)
if not res then
utilities.send_reply(self, msg, 'Please message me privately or [click here](http://telegram.me/' .. self.info.username .. '?start=help) for a list of commands.', true)
utilities.send_reply(self, msg, 'Bitte schreibe mir zuerst [privat](http://telegram.me/' .. self.info.username .. '?start=help) für eine Hilfe.', true)
elseif msg.chat.type ~= 'private' then
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
utilities.send_reply(self, msg, 'Ich habe dir die Hilfe per PN gesendet!.')
end
return
end
for _,plugin in ipairs(self.plugins) do
if plugin.command and utilities.get_word(plugin.command, 1) == input and plugin.doc then
local output = '*Help for* _' .. utilities.get_word(plugin.command, 1) .. '_ *:*\n' .. plugin.doc
local output = '*Hilfe für* _' .. utilities.get_word(plugin.command, 1) .. '_ *:*' .. plugin.doc
utilities.send_message(self, msg.chat.id, output, true, nil, true)
return
end
end
utilities.send_reply(self, msg, 'Sorry, there is no help for that command.')
utilities.send_reply(self, msg, 'Für diesen Befehl gibt es keine Hilfe.')
end

19
otouto/plugins/imdb.lua Executable file → Normal file
View File

@ -4,15 +4,15 @@ local HTTP = require('socket.http')
local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
local bindings = require('otouto.bindings')
imdb.command = 'imdb <query>'
function imdb:init(config)
imdb.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imdb', true).table
imdb.doc = [[```
]]..config.cmd_pat..[[imdb <query>
Returns an IMDb entry.
```]]
imdb.doc = [[*
]]..config.cmd_pat..[[imdb* _<Film>_
Sucht _Film_ bei IMDB]]
end
function imdb:action(msg, config)
@ -42,13 +42,18 @@ function imdb:action(msg, config)
return
end
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')*\n'
output = output .. jdat.imdbRating ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')* von '..jdat.Director..'\n'
output = output .. string.gsub(jdat.imdbRating, '%.', ',') ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
output = output .. '_' .. jdat.Plot .. '_\n'
output = output .. '[Read more.](http://imdb.com/title/' .. jdat.imdbID .. ')'
output = output .. '[IMDB-Seite besuchen](http://imdb.com/title/' .. jdat.imdbID .. ')'
utilities.send_message(self, msg.chat.id, output, true, nil, true)
if jdat.Poster ~= "N/A" then
local file = download_to_file(jdat.Poster)
bindings.sendPhoto(self, {chat_id = msg.chat.id}, {photo = file} )
end
end
return imdb

View File

@ -0,0 +1,71 @@
local imgblacklist = {}
local utilities = require('otouto.utilities')
local redis = (loadfile "./otouto/redis.lua")()
imgblacklist.command = 'imgblacklist'
function imgblacklist:init(config)
imgblacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imgblacklist', true).table
imgblacklist.doc = [[*
]]..config.cmd_pat..[[imgblacklist* _show_: Zeige Blacklist
*]]..config.cmd_pat..[[imgblacklist* _add_ _<Wort>_: Fügt Wort der Blacklist hinzu
*]]..config.cmd_pat..[[imgblacklist* _remove_ _<Wort>_: Entfernt Wort von der Blacklist]]
end
function imgblacklist:show_blacklist()
if not _blacklist[1] then
return "Keine Wörter geblacklisted!\nBlackliste welche mit `/imgblacklist add [Wort]`"
else
local sort_alph = function( a,b ) return a < b end
table.sort( _blacklist, sort_alph )
local blacklist = "Folgende Wörter stehen auf der Blacklist:\n"
for v,word in pairs(_blacklist) do
blacklist = blacklist..'- '..word..'\n'
end
return blacklist
end
end
function imgblacklist:add_blacklist(word)
print('Blacklisting '..word..' - saving to redis set telegram:img_blacklist')
if redis:sismember("telegram:img_blacklist", word) == true then
return '"'..word..'" steht schon auf der Blacklist.'
else
redis:sadd("telegram:img_blacklist", word)
return '"'..word..'" blacklisted!'
end
end
function imgblacklist:remove_blacklist(word)
print('De-blacklisting '..word..' - removing from redis set telegram:img_blacklist')
if redis:sismember("telegram:img_blacklist", word) == true then
redis:srem("telegram:img_blacklist", word)
return '"'..word..'" erfolgreich von der Blacklist gelöscht!'
else
return '"'..word..'" steht nicht auf der Blacklist.'
end
end
function imgblacklist:action(msg)
local input = utilities.input(msg.text)
local input = string.lower(input)
_blacklist = redis:smembers("telegram:img_blacklist")
if input:match('(add) (.*)') then
local word = input:match('add (.*)')
output = imgblacklist:add_blacklist(word)
elseif input:match('(remove) (.*)') then
local word = input:match('remove (.*)')
output = imgblacklist:remove_blacklist(word)
elseif input:match('(show)') then
output = imgblacklist:show_blacklist()
else
utilities.send_message(self, msg.chat.id, imgblacklist.doc, true, msg.message_id, true)
return
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
end
return imgblacklist

0
otouto/plugins/lastfm.lua Executable file → Normal file
View File

0
otouto/plugins/nick.lua Executable file → Normal file
View File

0
otouto/plugins/ping.lua Executable file → Normal file
View File

0
otouto/plugins/pokedex.lua Executable file → Normal file
View File

0
otouto/plugins/pun.lua Executable file → Normal file
View File

0
otouto/plugins/reactions.lua Executable file → Normal file
View File

0
otouto/plugins/reddit.lua Executable file → Normal file
View File

55
otouto/plugins/set.lua Normal file
View File

@ -0,0 +1,55 @@
local set = {}
local utilities = require('otouto.utilities')
local redis = (loadfile "./otouto/redis.lua")()
set.command = 'set <Variable> <Wert>'
function set:init(config)
set.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true).table
set.doc = [[*
]]..config.cmd_pat..[[set* _<Variable>_ _<Wert>_: Speichert eine Variable mit einem Wert
*]]..config.cmd_pat..[[set* _<Variable>_ _nil_: Löscht Variable
Nutze `!get <Variable>` zum Abrufen]]
end
function set:save_value(msg, name, value)
local hash = get_redis_hash(msg, 'variables')
if hash then
print('Saving variable to redis hash '..hash)
redis:hset(hash, name, value)
return "Gespeichert: "..name.." = "..value
end
end
function set:delete_value(msg, name)
local hash = get_redis_hash(msg, 'variables')
if redis:hexists(hash, name) == true then
print('Deleting variable from redis hash '..hash)
redis:hdel(hash, name)
return 'Variable "'..name..'" erfolgreich gelöscht!'
else
return 'Du kannst keine Variable löschen, die nicht existiert .-.'
end
end
function set:action(msg)
local input = utilities.input(msg.text)
if not input:match('([^%s]+) (.+)') then
utilities.send_message(self, msg.chat.id, set.doc, true, msg.message_id, true)
return
end
local name = input:match('([^%s]+) ')
local value = input:match(' (.+)')
if value == "nil" then
output = set:delete_value(msg, name)
else
output = set:save_value(msg, name, value)
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
end
return set

View File

@ -1,72 +0,0 @@
local setandget = {}
local utilities = require('otouto.utilities')
function setandget:init(config)
self.database.setandget = self.database.setandget or {}
setandget.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true):t('get', true).table
setandget.doc = [[```
]]..config.cmd_pat..[[set <name> <value>
Stores a value with the given name. Use "]]..config.cmd_pat..[[set <name> --" to delete the stored value.
]]..config.cmd_pat..[[get [name]
Returns the stored value or a list of stored values.
```]]
end
setandget.command = 'set <name> <value>'
function setandget:action(msg, config)
local input = utilities.input(msg.text)
self.database.setandget[msg.chat.id_str] = self.database.setandget[msg.chat.id_str] or {}
if msg.text_lower:match('^'..config.cmd_pat..'set') then
if not input then
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
return
end
local name = utilities.get_word(input:lower(), 1)
local value = utilities.input(input)
if not name or not value then
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
elseif value == '--' or value == '' then
self.database.setandget[msg.chat.id_str][name] = nil
utilities.send_message(self, msg.chat.id, 'That value has been deleted.')
else
self.database.setandget[msg.chat.id_str][name] = value
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
end
elseif msg.text_lower:match('^'..config.cmd_pat..'get') then
if not input then
local output
if utilities.table_size(self.database.setandget[msg.chat.id_str]) == 0 then
output = 'No values have been stored here.'
else
output = '*List of stored values:*\n'
for k,v in pairs(self.database.setandget[msg.chat.id_str]) do
output = output .. '' .. k .. ': `' .. v .. '`\n'
end
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
return
end
local output
if self.database.setandget[msg.chat.id_str][input:lower()] then
output = '`' .. self.database.setandget[msg.chat.id_str][input:lower()] .. '`'
else
output = 'There is no value stored by that name.'
end
utilities.send_message(self, msg.chat.id, output, true, nil, true)
end
end
return setandget

View File

@ -3,26 +3,26 @@ local shell = {}
local utilities = require('otouto.utilities')
function shell:init(config)
shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('run', true).table
shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('sh', true).table
end
function shell:action(msg, config)
if msg.from.id ~= config.admin then
return
utilities.send_reply(self, msg, config.errors.sudo)
end
local input = utilities.input(msg.text)
input = input:gsub('', '--')
if not input then
utilities.send_reply(self, msg, 'Please specify a command to run.')
utilities.send_reply(self, msg, 'Bitte gebe ein Kommando ein.')
return
end
local output = io.popen(input):read('*all')
if output:len() == 0 then
output = 'Done!'
output = 'Ausgeführt.'
else
output = '```\n' .. output .. '\n```'
end

0
otouto/plugins/slap.lua Executable file → Normal file
View File

0
otouto/plugins/time.lua Executable file → Normal file
View File

0
otouto/plugins/translate.lua Executable file → Normal file
View File

156
otouto/plugins/twitter.lua Normal file
View File

@ -0,0 +1,156 @@
local twitter = {}
local utilities = require('otouto.utilities')
local HTTPS = require('ssl.https')
local JSON = require('dkjson')
local redis = (loadfile "./otouto/redis.lua")()
local OAuth = (require "OAuth")
local bindings = require('otouto.bindings')
function twitter:init(config)
if not cred_data.tw_consumer_key then
print('Missing config value: tw_consumer_key.')
print('twitter.lua will not be enabled.')
return
elseif not cred_data.tw_consumer_secret then
print('Missing config value: tw_consumer_secret.')
print('twitter.lua will not be enabled.')
return
elseif not cred_data.tw_access_token then
print('Missing config value: tw_access_token.')
print('twitter.lua will not be enabled.')
return
elseif not cred_data.tw_access_token_secret then
print('Missing config value: tw_access_token_secret.')
print('twitter.lua will not be enabled.')
return
end
twitter.triggers = {
'twitter.com/[^/]+/statuse?s?/([0-9]+)'
}
twitter.doc = [[*Twitter-Link*: Postet Tweet]]
end
local consumer_key = cred_data.tw_consumer_key
local consumer_secret = cred_data.tw_consumer_secret
local access_token = cred_data.tw_access_token
local access_token_secret = cred_data.tw_access_token_secret
local client = OAuth.new(consumer_key, consumer_secret, {
RequestToken = "https://api.twitter.com/oauth/request_token",
AuthorizeUser = {"https://api.twitter.com/oauth/authorize", method = "GET"},
AccessToken = "https://api.twitter.com/oauth/access_token"
}, {
OAuthToken = access_token,
OAuthTokenSecret = access_token_secret
})
function twitter:action(msg)
if not msg.text:match('twitter.com/[^/]+/statuse?s?/([0-9]+)') then
return
end
local id = msg.text:match('twitter.com/[^/]+/statuse?s?/([0-9]+)')
local twitter_url = "https://api.twitter.com/1.1/statuses/show/" .. id.. ".json"
local response_code, response_headers, response_status_line, response_body = client:PerformRequest("GET", twitter_url)
local response = JSON.decode(response_body)
local full_name = response.user.name
local user_name = response.user.screen_name
if response.user.verified then
verified = ''
else
verified = ''
end
-- MD: local header = 'Tweet von '..full_name..' ([@' ..user_name.. '](https://twitter.com/'..user_name..')'..verified..')\n'
local header = 'Tweet von '..full_name..' (@' ..user_name..verified..')\n'
local text = response.text
-- favorites & retweets
if response.retweet_count == 0 then
retweets = ""
else
retweets = response.retweet_count..'x retweeted'
end
if response.favorite_count == 0 then
favorites = ""
else
favorites = response.favorite_count..'x favorisiert'
end
if retweets == "" and favorites ~= "" then
footer = favorites
elseif retweets ~= "" and favorites == "" then
footer = retweets
elseif retweets ~= "" and favorites ~= "" then
footer = retweets..' - '..favorites
else
footer = ""
end
-- replace short URLs
if response.entities.urls then
for k, v in pairs(response.entities.urls) do
local short = v.url
local long = v.expanded_url
text = text:gsub(short, long)
end
end
-- remove images
local images = {}
local videos = {}
if response.entities.media and response.extended_entities.media then
for k, v in pairs(response.extended_entities.media) do
local url = v.url
local pic = v.media_url_https
if v.video_info then
if not v.video_info.variants[3] then
local vid = v.video_info.variants[1].url
table.insert(videos, vid)
else
local vid = v.video_info.variants[3].url
table.insert(videos, vid)
end
end
text = text:gsub(url, "")
table.insert(images, pic)
end
end
-- quoted tweet
if response.quoted_status then
local quoted_text = response.quoted_status.text
local quoted_name = response.quoted_status.user.name
local quoted_screen_name = response.quoted_status.user.screen_name
if response.quoted_status.user.verified then
quoted_verified = ''
else
quoted_verified = ''
end
-- MD: quote = 'Als Antwort auf '..quoted_name..' ([@' ..quoted_screen_name.. '](https://twitter.com/'..quoted_screen_name..')'..quoted_verified..'):\n'..quoted_text
quote = 'Als Antwort auf '..quoted_name..' (@' ..quoted_screen_name..quoted_verified..'):\n'..quoted_text
text = text..'\n\n'..quote..'\n'
end
-- send the parts
local text = unescape(text)
print(header .. "\n" .. text.."\n"..footer)
utilities.send_reply(self, msg, header .. "\n" .. text.."\n"..footer)
for k, v in pairs(images) do
local file = download_to_file(v)
bindings.sendPhoto(self, {chat_id = msg.chat.id}, {photo = file} )
os.remove(file)
print("Deleted: "..file)
end
for k, v in pairs(videos) do
local file = download_to_file(v)
bindings.sendVideo(self, {chat_id = msg.chat.id}, {video = file} )
os.remove(file)
print("Deleted: "..file)
end
end
return twitter

0
otouto/plugins/urbandictionary.lua Executable file → Normal file
View File

0
otouto/plugins/weather.lua Executable file → Normal file
View File

0
otouto/plugins/whoami.lua Executable file → Normal file
View File

20
otouto/plugins/wikipedia.lua Executable file → Normal file
View File

@ -5,20 +5,18 @@ local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
wikipedia.command = 'wikipedia <query>'
wikipedia.command = 'wiki <Begriff>'
function wikipedia:init(config)
wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true):t('w', true).table
wikipedia.doc = [[```
]]..config.cmd_pat..[[wikipedia <query>
Returns an article from Wikipedia.
Aliases: ]]..config.cmd_pat..[[w, ]]..config.cmd_pat..[[wiki
```]]
wikipedia.doc = [[*
]]..config.cmd_pat..[[wiki* _<Begriff>_: Gibt Wikipedia-Artikel aus
Aliase: ]]..config.cmd_pat..[[w, ]]..config.cmd_pat..[[wikipedia]]
end
local get_title = function(search)
for _,v in ipairs(search) do
if not v.snippet:match('may refer to:') then
if not v.snippet:match('steht für') then
return v.title
end
end
@ -46,7 +44,7 @@ function wikipedia:action(msg, config)
local jstr, res, jdat
-- All pretty standard from here.
local search_url = 'https://en.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch='
local search_url = 'https://de.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch='
jstr, res = HTTPS.request(search_url .. URL.escape(input))
if res ~= 200 then
@ -66,7 +64,7 @@ function wikipedia:action(msg, config)
return
end
local res_url = 'https://en.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exchars=4000&exsectionformat=plain&titles='
local res_url = 'https://de.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exchars=4000&exsectionformat=plain&titles='
jstr, res = HTTPS.request(res_url .. URL.escape(title))
if res ~= 200 then
@ -97,7 +95,7 @@ function wikipedia:action(msg, config)
-- first part of the text is the title, and if so, we embolden that.
-- Otherwise, we prepend the text with a bold title. Then we append a "Read
-- More" link.
local url = 'https://en.wikipedia.org/wiki/' .. URL.escape(title)
local url = 'https://de.wikipedia.org/wiki/' .. URL.escape(title)
title = title:gsub('%(.+%)', '')
local output
if string.match(text:sub(1, title:len()), title) then
@ -105,7 +103,7 @@ function wikipedia:action(msg, config)
else
output = '*' .. title:gsub('%(.+%)', '') .. '*\n' .. text:gsub('%[.+%]','')
end
output = output .. '\n[Read more.](' .. url:gsub('%)', '\\)') .. ')'
output = output .. '\n[Wikipedia - '..title..'](' .. url:gsub('%)', '\\)') .. ')'
utilities.send_message(self, msg.chat.id, output, true, nil, true)

0
otouto/plugins/xkcd.lua Executable file → Normal file
View File

0
otouto/plugins/youtube.lua Executable file → Normal file
View File

47
otouto/redis.lua Normal file
View File

@ -0,0 +1,47 @@
local Redis = require 'redis'
local FakeRedis = require 'fakeredis'
local params = {
'unix:///home/anditest/.redis/sock'
}
-- Overwrite HGETALL
Redis.commands.hgetall = Redis.command('hgetall', {
response = function(reply, command, ...)
local new_reply = { }
for i = 1, #reply, 2 do new_reply[reply[i]] = reply[i + 1] end
return new_reply
end
})
local redis = nil
-- Won't launch an error if fails
local ok = pcall(function()
redis = Redis.connect('unix:///home/anditest/.redis/sock') -- FUCKING FUCK REDIS LUA FUCK Y U NO WORK WITH PARAMS
end)
if not ok then
local fake_func = function()
print('\27[31mCan\'t connect with Redis, install/configure it!\27[39m')
end
fake_func()
fake = FakeRedis.new()
print('\27[31mRedis addr: '..params.host..'\27[39m')
print('\27[31mRedis port: '..params.port..'\27[39m')
redis = setmetatable({fakeredis=true}, {
__index = function(a, b)
if b ~= 'data' and fake[b] then
fake_func(b)
end
return fake[b] or fake_func
end })
end
return redis

248
otouto/utilities.lua Executable file → Normal file
View File

@ -8,7 +8,10 @@ local ltn12 = require('ltn12')
local HTTPS = require('ssl.https')
local URL = require('socket.url')
local JSON = require('dkjson')
local serpent = require("serpent")
local bindings = require('otouto.bindings')
local redis = (loadfile "./otouto/redis.lua")()
local mimetype = (loadfile "./otouto/mimetype.lua")()
-- For the sake of ease to new contributors and familiarity to old contributors,
-- we'll provide a couple of aliases to real bindings here.
@ -31,7 +34,6 @@ function utilities:send_reply(old_msg, text, use_markdown)
parse_mode = use_markdown and 'Markdown' or nil
} )
end
-- get the indexed word in a string
function utilities.get_word(s, i)
s = s or ''
@ -108,6 +110,92 @@ local lc_list = {
['!'] = 'ǃ'
}
-- http://www.lua.org/manual/5.2/manual.html#pdf-io.popen
function run_command(str)
local cmd = io.popen(str)
local result = cmd:read('*all')
cmd:close()
return result
end
function string.starts(String, Start)
return Start == string.sub(String,1,string.len(Start))
end
function get_http_file_name(url, headers)
-- Eg: fooo.var
local file_name = url:match("[^%w]+([%.%w]+)$")
-- Any delimited aphanumeric on the url
file_name = file_name or url:match("[^%w]+(%w+)[^%w]+$")
-- Random name, hope content-type works
file_name = file_name or str:random(5)
local content_type = headers["content-type"]
local extension = nil
if content_type then
extension = mimetype.get_mime_extension(content_type)
end
if extension then
file_name = file_name.."."..extension
end
local disposition = headers["content-disposition"]
if disposition then
-- attachment; filename=CodeCogsEqn.png
file_name = disposition:match('filename=([^;]+)') or file_name
file_name = string.gsub(file_name, "\"", "")
end
return file_name
end
-- Saves file to $HOME/tmp/. If file_name isn't provided,
-- will get the text after the last "/" for filename
-- and content-type for extension
function download_to_file(url, file_name)
print("url to download: "..url)
local respbody = {}
local options = {
url = url,
sink = ltn12.sink.table(respbody),
redirect = true
}
-- nil, code, headers, status
local response = nil
if string.starts(url, 'https') then
options.redirect = false
response = {HTTPS.request(options)}
else
response = {HTTP.request(options)}
end
local code = response[2]
local headers = response[3]
local status = response[4]
if code ~= 200 then return nil end
file_name = file_name or get_http_file_name(url, headers)
local file_path = "/home/anditest/tmp/telegram-bot/"..file_name
print("Saved to: "..file_path)
file = io.open(file_path, "w+")
file:write(table.concat(respbody))
file:close()
return file_path
end
function vardump(value)
print(serpent.block(value, {comment=false}))
end
-- Replaces letters with corresponding Cyrillic characters.
function utilities.latcyr(str)
for k,v in pairs(lc_list) do
@ -373,4 +461,162 @@ utilities.char = {
em_dash = ''
}
function get_redis_hash(msg, var)
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
return 'chat:'..msg.chat.id..':'..var
end
if msg.chat.type == 'private' then
return 'user:'..msg.from.id..':'..var
end
end
-- remove whitespace
function all_trim(s)
return s:match( "^%s*(.-)%s*$" )
end
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
function comma_value(amount)
local formatted = amount
while true do
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1.%2')
if (k==0) then
break
end
end
return formatted
end
function string.ends(str, fin)
return fin=='' or string.sub(str,-string.len(fin)) == fin
end
function cache_data(plugin, query, data, timeout, typ)
-- How to: cache_data(pluginname, query_name, data_to_cache, expire_in_seconds)
local hash = 'telegram:cache:'..plugin..':'..query
if timeout then
print('Caching "'..query..'" from plugin '..plugin..' (expires in '..timeout..' seconds)')
else
print('Caching "'..query..'" from plugin '..plugin..' (expires never)')
end
if typ == 'key' then
redis:set(hash, data)
elseif typ == 'set' then
-- make sure that you convert your data into a table:
-- {"foo", "bar", "baz"} instead of
-- {"bar" = "foo", "foo" = "bar", "bar" = "baz"}
-- because other formats are not supported by redis (or I haven't found a way to store them)
for _,str in pairs(data) do
redis:sadd(hash, str)
end
else
redis:hmset(hash, data)
end
if timeout then
redis:expire(hash, timeout)
end
end
--[[
Ordered table iterator, allow to iterate on the natural order of the keys of a
table.
-- http://lua-users.org/wiki/SortedIteration
]]
function __genOrderedIndex( t )
local orderedIndex = {}
for key in pairs(t) do
table.insert( orderedIndex, key )
end
table.sort( orderedIndex )
return orderedIndex
end
function orderedNext(t, state)
-- Equivalent of the next function, but returns the keys in the alphabetic
-- order. We use a temporary ordered key table that is stored in the
-- table being iterated.
key = nil
--print("orderedNext: state = "..tostring(state) )
if state == nil then
-- the first time, generate the index
t.__orderedIndex = __genOrderedIndex( t )
key = t.__orderedIndex[1]
else
-- fetch the next value
for i = 1,table.getn(t.__orderedIndex) do
if t.__orderedIndex[i] == state then
key = t.__orderedIndex[i+1]
end
end
end
if key then
return key, t[key]
end
-- no more value to return, cleanup
t.__orderedIndex = nil
return
end
function orderedPairs(t)
-- Equivalent of the pairs() function on tables. Allows to iterate
-- in order
return orderedNext, t, nil
end
-- converts total amount of seconds (e.g. 65 seconds) to human redable time (e.g. 1:05 minutes)
function makeHumanTime(totalseconds)
local seconds = totalseconds % 60
local minutes = math.floor(totalseconds / 60)
local minutes = minutes % 60
local hours = math.floor(totalseconds / 3600)
if minutes == 00 and hours == 00 then
return seconds..' Sekunden'
elseif hours == 00 and minutes ~= 00 then
return string.format("%02d:%02d", minutes, seconds)..' Minuten'
elseif hours ~= 00 then
return string.format("%02d:%02d:%02d", hours, minutes, seconds)..' Stunden'
end
end
function is_blacklisted(msg)
_blacklist = redis:smembers("telegram:img_blacklist")
local var = false
for v,word in pairs(_blacklist) do
if string.find(string.lower(msg), string.lower(word)) then
print("Wort steht auf der Blacklist!")
var = true
break
end
end
return var
end
function unescape(str)
str = string.gsub( str, '&lt;', '<' )
str = string.gsub( str, '&gt;', '>' )
str = string.gsub( str, '&quot;', '"' )
str = string.gsub( str, '&apos;', "'" )
str = string.gsub( str, "&Auml;", "Ä")
str = string.gsub( str, "&auml;", "ä")
str = string.gsub( str, "&Ouml;", "Ö")
str = string.gsub( str, "&ouml;", "ö")
str = string.gsub( str, "Uuml;", "Ü")
str = string.gsub( str, "&uuml;", "ü")
str = string.gsub( str, "&szlig;", "ß")
str = string.gsub( str, '&#(%d+);', function(n) return string.char(n) end )
str = string.gsub( str, '&#x(%d+);', function(n) return string.char(tonumber(n,16)) end )
str = string.gsub( str, '&amp;', '&' ) -- Be sure to do this after all others
return str
end
return utilities

0
tg-install.sh Executable file → Normal file
View File

0
tg-launch.sh Executable file → Normal file
View File