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:
parent
31a8e220ac
commit
a4d7c40ad9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
otouto/plugins/mokubot*
|
||||
config.lua
|
||||
*.db
|
||||
tg
|
||||
|
2
README.md
Executable file → Normal file
2
README.md
Executable file → Normal 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
56
config.lua → config.lua.example
Executable file → Normal 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
otouto/bindings.lua
Executable file → Normal file
0
otouto/bindings.lua
Executable file → Normal file
56
otouto/bot.lua
Executable file → Normal file
56
otouto/bot.lua
Executable file → Normal 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
100
otouto/mimetype.lua
Normal 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
41
otouto/plugins/9gag.lua
Normal 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
4
otouto/plugins/about.lua
Executable file → Normal 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
49
otouto/plugins/adfly.lua
Normal 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
0
otouto/plugins/apod.lua
Executable file → Normal file
0
otouto/plugins/bandersnatch.lua
Executable file → Normal file
0
otouto/plugins/bandersnatch.lua
Executable file → Normal file
0
otouto/plugins/bible.lua
Executable file → Normal file
0
otouto/plugins/bible.lua
Executable file → Normal file
0
otouto/plugins/blacklist.lua
Executable file → Normal file
0
otouto/plugins/blacklist.lua
Executable file → Normal file
0
otouto/plugins/calc.lua
Executable file → Normal file
0
otouto/plugins/calc.lua
Executable file → Normal file
0
otouto/plugins/cats.lua
Executable file → Normal file
0
otouto/plugins/cats.lua
Executable file → Normal file
0
otouto/plugins/chatter.lua
Executable file → Normal file
0
otouto/plugins/chatter.lua
Executable file → Normal file
0
otouto/plugins/commit.lua
Executable file → Normal file
0
otouto/plugins/commit.lua
Executable file → Normal file
0
otouto/plugins/currency.lua
Executable file → Normal file
0
otouto/plugins/currency.lua
Executable file → Normal file
0
otouto/plugins/dice.lua
Executable file → Normal file
0
otouto/plugins/dice.lua
Executable file → Normal file
0
otouto/plugins/echo.lua
Executable file → Normal file
0
otouto/plugins/echo.lua
Executable file → Normal file
0
otouto/plugins/eightball.lua
Executable file → Normal file
0
otouto/plugins/eightball.lua
Executable file → Normal file
0
otouto/plugins/fortune.lua
Executable file → Normal file
0
otouto/plugins/fortune.lua
Executable file → Normal file
94
otouto/plugins/gImages.lua
Executable file → Normal file
94
otouto/plugins/gImages.lua
Executable file → Normal 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
|
||||
|
||||
print ('Checking if search contains blacklisted word: '..input)
|
||||
if is_blacklisted(input) then
|
||||
utilities.send_reply(self, msg, 'Vergiss es! ._.')
|
||||
return
|
||||
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
|
||||
|
||||
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
|
||||
url = url .. '&safe=high'
|
||||
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 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 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)
|
||||
|
||||
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 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
0
otouto/plugins/gMaps.lua
Executable file → Normal file
112
otouto/plugins/gSearch.lua
Executable file → Normal file
112
otouto/plugins/gSearch.lua
Executable file → Normal 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
|
||||
|
||||
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('&', '&')
|
||||
--[[
|
||||
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)
|
||||
end
|
||||
|
||||
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
59
otouto/plugins/get.lua
Normal 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
0
otouto/plugins/greetings.lua
Executable file → Normal file
0
otouto/plugins/hackernews.lua
Executable file → Normal file
0
otouto/plugins/hackernews.lua
Executable file → Normal file
0
otouto/plugins/hearthstone.lua
Executable file → Normal file
0
otouto/plugins/hearthstone.lua
Executable file → Normal file
16
otouto/plugins/help.lua
Executable file → Normal file
16
otouto/plugins/help.lua
Executable file → Normal 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
19
otouto/plugins/imdb.lua
Executable file → Normal 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,12 +42,17 @@ 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
|
||||
|
||||
|
71
otouto/plugins/imgblacklist.lua
Normal file
71
otouto/plugins/imgblacklist.lua
Normal 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
0
otouto/plugins/lastfm.lua
Executable file → Normal file
0
otouto/plugins/nick.lua
Executable file → Normal file
0
otouto/plugins/nick.lua
Executable file → Normal file
0
otouto/plugins/ping.lua
Executable file → Normal file
0
otouto/plugins/ping.lua
Executable file → Normal file
0
otouto/plugins/pokedex.lua
Executable file → Normal file
0
otouto/plugins/pokedex.lua
Executable file → Normal file
0
otouto/plugins/pun.lua
Executable file → Normal file
0
otouto/plugins/pun.lua
Executable file → Normal file
0
otouto/plugins/reactions.lua
Executable file → Normal file
0
otouto/plugins/reactions.lua
Executable file → Normal file
0
otouto/plugins/reddit.lua
Executable file → Normal file
0
otouto/plugins/reddit.lua
Executable file → Normal file
55
otouto/plugins/set.lua
Normal file
55
otouto/plugins/set.lua
Normal 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
|
@ -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
|
@ -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
0
otouto/plugins/slap.lua
Executable file → Normal file
0
otouto/plugins/time.lua
Executable file → Normal file
0
otouto/plugins/time.lua
Executable file → Normal file
0
otouto/plugins/translate.lua
Executable file → Normal file
0
otouto/plugins/translate.lua
Executable file → Normal file
156
otouto/plugins/twitter.lua
Normal file
156
otouto/plugins/twitter.lua
Normal 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
0
otouto/plugins/urbandictionary.lua
Executable file → Normal file
0
otouto/plugins/weather.lua
Executable file → Normal file
0
otouto/plugins/weather.lua
Executable file → Normal file
0
otouto/plugins/whoami.lua
Executable file → Normal file
0
otouto/plugins/whoami.lua
Executable file → Normal file
20
otouto/plugins/wikipedia.lua
Executable file → Normal file
20
otouto/plugins/wikipedia.lua
Executable file → Normal 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
0
otouto/plugins/xkcd.lua
Executable file → Normal file
0
otouto/plugins/youtube.lua
Executable file → Normal file
0
otouto/plugins/youtube.lua
Executable file → Normal file
47
otouto/redis.lua
Normal file
47
otouto/redis.lua
Normal 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
248
otouto/utilities.lua
Executable file → Normal 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, '<', '<' )
|
||||
str = string.gsub( str, '>', '>' )
|
||||
str = string.gsub( str, '"', '"' )
|
||||
str = string.gsub( str, ''', "'" )
|
||||
str = string.gsub( str, "Ä", "Ä")
|
||||
str = string.gsub( str, "ä", "ä")
|
||||
str = string.gsub( str, "Ö", "Ö")
|
||||
str = string.gsub( str, "ö", "ö")
|
||||
str = string.gsub( str, "Uuml;", "Ü")
|
||||
str = string.gsub( str, "ü", "ü")
|
||||
str = string.gsub( str, "ß", "ß")
|
||||
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, '&', '&' ) -- Be sure to do this after all others
|
||||
return str
|
||||
end
|
||||
|
||||
return utilities
|
||||
|
0
tg-install.sh
Executable file → Normal file
0
tg-install.sh
Executable file → Normal file
0
tg-launch.sh
Executable file → Normal file
0
tg-launch.sh
Executable file → Normal file
Reference in New Issue
Block a user