diff --git a/otouto/plugins/afk.lua b/otouto/plugins/afk.lua index d2f615f..1483fe2 100644 --- a/otouto/plugins/afk.lua +++ b/otouto/plugins/afk.lua @@ -62,8 +62,8 @@ function afk:switch_afk(user_name, user_id, chat_id, timestamp, text) end function afk:pre_process(msg, self) - if msg.chat.type == "private" then - -- Ignore + if msg.chat.type == "private" then + -- Ignore return end diff --git a/otouto/plugins/gImages.lua b/otouto/plugins/gImages.lua index 20ce55c..484ed02 100644 --- a/otouto/plugins/gImages.lua +++ b/otouto/plugins/gImages.lua @@ -20,7 +20,7 @@ function gImages:init(config) return end - gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('img', true):t('i', true):t('insfw', true).table + gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('img', true):t('i', true).table gImages.doc = [[* ]]..config.cmd_pat..[[img* __ Sucht Bild mit Google und versendet es (SafeSearch aktiv) diff --git a/otouto/plugins/lyrics.lua b/otouto/plugins/lyrics.lua new file mode 100644 index 0000000..59bc49b --- /dev/null +++ b/otouto/plugins/lyrics.lua @@ -0,0 +1,51 @@ +local lyrics = {} + +local http = require('socket.http') +local json = require('dkjson') +local utilities = require('otouto.utilities') + +function lyrics:init(config) + if not cred_data.lyricsnmusic_apikey then + print('Missing config value: lyricsnmusic_apikey.') + print('lyrics.lua will not be enabled.') + return + end + + lyrics.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lyrics', true).table + lyrics.doc = [[* +]]..config.cmd_pat..[[lyrics* __: Postet Liedertext]] +end + +lyrics.command = 'lyrics ' + +function lyrics:getLyrics(text) + local apikey = cred_data.lyricsnmusic_apikey + local q = url_encode(text) + local b = http.request("http://api.lyricsnmusic.com/songs?api_key="..apikey.."&q=" .. q) + response = json.decode(b) + local reply = "" + if #response > 0 then + -- grab first match + local result = response[1] + reply = result.title .. " - " .. result.artist.name .. "\n" .. result.snippet .. "\n[Ganzen Liedertext ansehen](" .. result.url .. ")" + else + reply = nil + end + return reply +end + +function lyrics:action(msg, config, matches) + 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, lyrics.doc, true, msg.message_id, true) + return + end + end + + utilities.send_reply(self, msg, lyrics:getLyrics(input), true) +end + +return lyrics diff --git a/otouto/plugins/magische_miesmuschel.lua b/otouto/plugins/magische_miesmuschel.lua new file mode 100644 index 0000000..a7be099 --- /dev/null +++ b/otouto/plugins/magische_miesmuschel.lua @@ -0,0 +1,23 @@ +local muschel = {} + +local utilities = require('otouto.utilities') + +muschel.triggers = { + "^[Mm][Aa][Gg][Ii][Ss][Cc][Hh][Ee] [Mm][Ii][Ee][Ss][Mm][Uu][Ss][Cc][Hh][Ee][Ll], (.*)$" +} + +function muschel:frag_die_muschel() + local possibilities = { + "Ja", + "Nein", + "Eines Tages vielleicht" + } + local random = math.random(3) + return possibilities[random] +end + +function muschel:action(msg, config, matches) + utilities.send_reply(self, msg, muschel:frag_die_muschel()) +end + +return muschel diff --git a/otouto/plugins/minecraft_server.lua b/otouto/plugins/minecraft_server.lua new file mode 100644 index 0000000..b5b8bec --- /dev/null +++ b/otouto/plugins/minecraft_server.lua @@ -0,0 +1,86 @@ +local mc_server = {} + +local http = require('socket.http') +local ltn12 = require('ltn12') +local URL = require('socket.url') +local json = require('dkjson') +local utilities = require('otouto.utilities') + +function mc_server:init(config) + mc_server.triggers = { + "^/mine (.*)$" + } + mc_server.doc = [[* +]]..config.cmd_pat..[[mine* __: Sucht Minecraft-Server und sendet Infos. Standard-Port: 25565 +*]]..config.cmd_pat..[[mine* __ __: Sucht Minecraft-Server auf Port und sendet Infos. +]] +end + +mc_server.command = "mine [Port]" + +function mc_server:mineSearch(ip, port) + local responseText = "" + local api = "https://mcapi.us/server/status" + local parameters = "?ip="..(URL.escape(ip) or "").."&port="..(URL.escape(port) or "").."&players=true" + local respbody = {} + local body, code, headers, status = http.request{ + url = api..parameters, + method = "GET", + redirect = true, + sink = ltn12.sink.table(respbody) + } + local body = table.concat(respbody) + if (status == nil) then return "FEHLER: status = nil" end + if code ~=200 then return "FEHLER: "..code..". Status: "..status end + local jsonData = json.decode(body) + responseText = responseText..ip..":"..port..":\n" + if (jsonData.motd ~= nil and jsonData.motd ~= '') then + local tempMotd = "" + tempMotd = jsonData.motd:gsub('%ยง.', '') + if (jsonData.motd ~= nil) then responseText = responseText.."*MOTD*: "..tempMotd.."\n" end + end + if (jsonData.online ~= nil) then + if jsonData.online == true then + server_online = "Ja" + else + server_online = "Nein" + end + responseText = responseText.."*Online*: "..server_online.."\n" + end + if (jsonData.players ~= nil) then + if (jsonData.players.max ~= nil and jsonData.players.max ~= 0) then + responseText = responseText.."*Slots*: "..jsonData.players.max.."\n" + end + if (jsonData.players.now ~= nil and jsonData.players.max ~= 0) then + responseText = responseText.."*Spieler online*: "..jsonData.players.now.."\n" + end + if (jsonData.players.sample ~= nil and jsonData.players.sample ~= false) then + responseText = responseText.."*Spieler*: "..table.concat(jsonData.players.sample, ", ").."\n" + end + if (jsonData.server.name ~= nil and jsonData.server.name ~= "") then + responseText = responseText.."*Server*: "..jsonData.server.name.."\n" + end + end + return responseText +end + +function mc_server:parseText(text, mc_server) + if (text == nil or text == "/mine") then + return mc_server.doc + end + ip, port = string.match(text, "^/mine (.-) (.*)$") + if (ip ~= nil and port ~= nil) then + return mc_server:mineSearch(ip, port) + end + local ip = string.match(text, "^/mine (.*)$") + if (ip ~= nil) then + return mc_server:mineSearch(ip, "25565") + end + return "FEHLER: Keine Input IP!" +end + +function mc_server:action(msg, config, matches) + utilities.send_reply(self, msg, mc_server:parseText(msg.text, mc_server), true) +end + +return mc_server diff --git a/otouto/plugins/minecraft_skin.lua b/otouto/plugins/minecraft_skin.lua new file mode 100644 index 0000000..d2898f6 --- /dev/null +++ b/otouto/plugins/minecraft_skin.lua @@ -0,0 +1,31 @@ +local mc_skin = {} + +local utilities = require('otouto.utilities') + +function mc_skin:init(config) + mc_skin.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('skin', true).table + mc_skin.doc = [[* +]]..config.cmd_pat..[[skin* __: Sendet Minecraft-Skin dieses Nutzers]] +end + +mc_skin.command = 'skin ' + +local BASE_URL = 'http://ip-api.com/json' + +function mc_skin:action(msg, config, matches) + 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, mc_skin.doc, true, msg.message_id, true) + return + end + end + + local url = 'http://www.minecraft-skin-viewer.net/3d.php?layers=true&aa=true&a=0&w=330&wt=10&abg=330&abd=40&ajg=340&ajd=20&ratio=13&format=png&login='..input..'&headOnly=false&displayHairs=true&randomness=341.png' + local file = download_to_file(url) + utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id) +end + +return mc_skin diff --git a/otouto/plugins/notify.lua b/otouto/plugins/notify.lua new file mode 100644 index 0000000..8530a8f --- /dev/null +++ b/otouto/plugins/notify.lua @@ -0,0 +1,102 @@ +-- INFO: Stats must be activated, so that it can collect all members of a group and save his/her id to redis. +-- You can deactivate it afterwards. + +local notify = {} + +local redis = (loadfile "./otouto/redis.lua")() +local utilities = require('otouto.utilities') + +function notify:init(config) + notify.triggers = { + "^/notify (del)$", + "^/notify$" + } + + notify.doc = [[* +]]..config.cmd_pat..[[notify* (del): Benachrichtigt dich privat, wenn du erwähnt wirst (bzw. schaltet das Feature wieder aus)]] +end + +notify.command = 'notify [del]' + +-- See https://stackoverflow.com/a/32854917 +function isWordFoundInString(word,input) + return select(2,input:gsub('^' .. word .. '%W+','')) + + select(2,input:gsub('%W+' .. word .. '$','')) + + select(2,input:gsub('^' .. word .. '$','')) + + select(2,input:gsub('%W+' .. word .. '%W+','')) > 0 +end + +function notify:pre_process(msg, self) + local notify_users = redis:smembers('notify:ls') + + -- I call this beautiful lady the "if soup" + if msg.chat.type == 'chat' or msg.chat.type == 'supergroup' then + if msg.text then + for _,user in pairs(notify_users) do + if isWordFoundInString('@'..user, string.lower(msg.text)) then + local chat_id = msg.chat.id + local id = redis:hget('notify:'..user, 'id') + -- check, if user has sent at least one message to the group, + -- so that we don't send the user some private text, when he/she is not + -- in the group. + if redis:sismember('chat:'..chat_id..':users', id) then + + -- ignore message, if user is mentioning him/herself + if id == tostring(msg.from.id) then break; end + + local send_date = run_command('date -d @'..msg.date..' +"%d.%m.%Y um %H:%M:%S Uhr"') + local send_date = string.gsub(send_date, "\n", "") + local from = string.gsub(msg.from.name, "%_", " ") + local chat_name = string.gsub(msg.chat.title, "%_", " ") + local text = from..' am '..send_date..' in "'..chat_name..'":\n\n'..msg.text + utilities.send_message(self, id, text) + end + end + end + end + end + + return msg +end + +function notify:action(msg, config, matches) + if not msg.from.username then + return 'Du hast keinen Usernamen und kannst daher dieses Feature nicht nutzen. Tut mir leid!' + end + + local username = string.lower(msg.from.username) + + local hash = 'notify:'..username + + if matches[1] == "del" then + if not redis:sismember('notify:ls', username) then + utilities.send_reply(self, msg, 'Du wirst noch gar nicht benachrichtigt!') + return + end + print('Setting notify in redis hash '..hash..' to false') + redis:hset(hash, 'notify', false) + print('Removing '..username..' from redis set notify:ls') + redis:srem('notify:ls', username) + utilities.send_reply(self, msg, 'Du erhälst jetzt keine Benachrichtigungen mehr, wenn du angesprochen wirst.') + return + else + if redis:sismember('notify:ls', username) then + utilities.send_reply(self, msg, 'Du wirst schon benachrichtigt!') + return + end + print('Setting notify in redis hash '..hash..' to true') + redis:hset(hash, 'notify', true) + print('Setting id in redis hash '..hash..' to '..msg.from.id) + redis:hset(hash, 'id', msg.from.id) + print('Adding '..username..' to redis set notify:ls') + redis:sadd('notify:ls', username) + local res = utilities.send_message(self, msg.from.id, 'Du erhälst jetzt Benachrichtigungen, wenn du angesprochen wirst, nutze `/notify del` zum Deaktivieren.', true, nil, true) + if not res then + utilities.send_reply(self, msg, 'Bitte schreibe mir [privat](http://telegram.me/' .. self.info.username .. '?start=about), um den Vorgang abzuschließen.', true) + elseif msg.chat.type ~= 'private' then + utilities.send_reply(self, msg, 'Du erhälst jetzt Benachrichtigungen, wenn du angesprochen wirst, nutze `/notify del` zum Deaktivieren.', true) + end + end +end + +return notify \ No newline at end of file diff --git a/otouto/plugins/pagespeed_insights.lua b/otouto/plugins/pagespeed_insights.lua new file mode 100644 index 0000000..7eb5593 --- /dev/null +++ b/otouto/plugins/pagespeed_insights.lua @@ -0,0 +1,39 @@ +local pagespeed_insights = {} + +local https = require('ssl.https') +local json = require('dkjson') +local utilities = require('otouto.utilities') + +function pagespeed_insights:init(config) + if not cred_data.google_apikey then + print('Missing config value: google_apikey.') + print('pagespeed_insights.lua will not be enabled.') + return + end + + pagespeed_insights.triggers = { + "^/speed (https?://[%w-_%.%?%.:/%+=&]+)" + } + pagespeed_insights.doc = [[* +]]..config.cmd_pat..[[speed* __: Testet Geschwindigkeit der Seite mit PageSpeed Insights]] +end + +local BASE_URL = 'https://www.googleapis.com/pagespeedonline/v2' + +function pagespeed_insights:get_pagespeed(test_url) + local apikey = cred_data.google_apikey + local url = BASE_URL..'/runPagespeed?url='..test_url..'&key='..apikey..'&fields=id,ruleGroups(SPEED(score))' + local res,code = https.request(url) + if code ~= 200 then return "HTTP-FEHLER" end + local data = json.decode(res) + return data.id..' hat einen PageSpeed-Score von *'..data.ruleGroups.SPEED.score..' Punkten.*' +end + +function pagespeed_insights:action(msg, config, matches) + utilities.send_typing(self, msg.chat.id, 'typing') + local text = pagespeed_insights:get_pagespeed(matches[1]) + if not text then utilities.send_reply(self, msg, config.errors.connection) return end + utilities.send_reply(self, msg, text, true) +end + +return pagespeed_insights diff --git a/otouto/plugins/pixabay.lua b/otouto/plugins/pixabay.lua new file mode 100644 index 0000000..26f5787 --- /dev/null +++ b/otouto/plugins/pixabay.lua @@ -0,0 +1,120 @@ +local pixabay = {} + +local https = require('ssl.https') +local json = require('dkjson') +local utilities = require('otouto.utilities') +local redis = (loadfile "./otouto/redis.lua")() + +function pixabay:init(config) + if not cred_data.pixabay_apikey then + print('Missing config value: pixabay_apikey.') + print('pixabay.lua will not be enabled.') + return + end + + pixabay.triggers = { + "^/pix(id) (%d+)", + "^/pix (.*)$", + "(pixabay.com).*%-(%d+)" + } + pixabay.doc = [[* +]]..config.cmd_pat..[[pix* __: Sendet lizenzfreies Bild]] +end + +pixabay.command = 'pix ' + +local BASE_URL = 'https://pixabay.com/api' +local apikey = cred_data.pixabay_apikey + +function pixabay:get_pixabay_directlink(id) + local url = BASE_URL..'/?key='..apikey..'&lang=de&id='..id + local b,c = https.request(url) + if c ~= 200 then return nil end + local data = json.decode(b) + if data.totalHits == 0 then return 'NOPIX' end + + local webformatURL = data.hits[1].webformatURL + local image_url = string.gsub(webformatURL, '_640.jpg', '_960.jpg') + + -- Link to full, high resolution image + local preview_url = data.hits[1].previewURL + local image_code = string.sub(preview_url, 59) + local image_code = string.sub(image_code, 0, -9) + local full_url = 'https://pixabay.com/de/photos/download/'..image_code..'.jpg' + + local user = data.hits[1].user + local tags = data.hits[1].tags + local page_url = data.hits[1].pageURL + + -- cache this shit + local hash = 'telegram:cache:pixabay:'..id + print('Caching data in '..hash..' with timeout 1209600') + redis:hset(hash, 'image_url', image_url) + redis:hset(hash, 'full_url', full_url) + redis:hset(hash, 'page_url', page_url) + redis:hset(hash, 'user', user) + redis:hset(hash, 'tags', tags) + redis:expire(hash, 1209600) -- 1209600 = two weeks + + return image_url, full_url, page_url, user, tags +end + +function pixabay:get_pixabay(term) + local count = 70 -- how many pictures should be returned (3 to 200) NOTE: more pictures = higher load time + local url = BASE_URL..'/?key='..apikey..'&lang=de&safesearch=true&per_page='..count..'&image_type=photo&q='..term + local b,c = https.request(url) + if c ~= 200 then return nil end + local photo = json.decode(b) + if photo.totalHits == 0 then return 'NOPIX' end + local photos = photo.hits + -- truly randomize + math.randomseed(os.time()) + -- random max json table size + local i = math.random(#photos) + + local webformatURL = photos[i].webformatURL + local image_url = string.gsub(webformatURL, '_640.jpg', '_960.jpg') + + -- Link to full, high resolution image + local preview_url = photos[i].previewURL + local image_code = string.sub(preview_url, 59) + local image_code = string.sub(image_code, 0, -9) + local full_url = 'https://pixabay.com/de/photos/download/'..image_code..'.jpg' + + local user = photos[i].user + local tags = photos[i].tags + local page_url = photos[i].pageURL + + return image_url, full_url, page_url, user, tags +end + +function pixabay:action(msg, config, matches) + local term = matches[1] + if matches[2] then + if redis:exists("telegram:cache:pixabay:"..matches[2]) == true then -- if cached + local hash = 'telegram:cache:pixabay:'..matches[2] + url = redis:hget(hash, 'image_url') + full_url = redis:hget(hash, 'full_url') + page_url = redis:hget(hash, 'page_url') + user = redis:hget(hash, 'user') + tags = redis:hget(hash, 'tags') + else + url, full_url, page_url, user, tags = pixabay:get_pixabay_directlink(matches[2]) + end + else + url, full_url, page_url, user, tags = pixabay:get_pixabay(term) + end + + if url == 'NOPIX' then + utilities.send_reply(self, msg, config.errors.results) + return + else + utilities.send_typing(self, msg.chat.id, 'upload_photo') + local file = download_to_file(url) + local text = tags..' von '..user..':\nSeite: '..page_url..'\nVoll: '..full_url..' (Login notwendig)' + utilities.send_photo(self, msg.chat.id, file, text, msg.message_id) + return + end +end + +return pixabay diff --git a/otouto/plugins/play_store.lua b/otouto/plugins/play_store.lua new file mode 100644 index 0000000..b198090 --- /dev/null +++ b/otouto/plugins/play_store.lua @@ -0,0 +1,62 @@ +local play_store = {} + +local https = require('ssl.https') +local json = require('dkjson') +local utilities = require('otouto.utilities') + +function play_store:init(config) + if not cred_data.x_mashape_key then + print('Missing config value: x_mashape_key.') + print('play_store.lua will not be enabled.') + return + end + + play_store.triggers = { + "play.google.com/store/apps/details%?id=(.*)" + } +end + +local BASE_URL = 'https://apps.p.mashape.com/google/application' + +function play_store:get_playstore_data (appid) + local apikey = cred_data.x_mashape_key + local url = BASE_URL..'/'..appid..'?mashape-key='..apikey + local res,code = https.request(url) + if code ~= 200 then return nil end + local data = json.decode(res).data + return data +end + +function play_store:send_playstore_data(data) + local title = data.title + local developer = data.developer.id + local category = data.category.name + local rating = data.rating.average + local installs = data.performance.installs + local description = data.description + if data.version == "Varies with device" then + appversion = "variiert je nach Gerät" + else + appversion = data.version + end + if data.price == 0 then + price = "Gratis" + else + price = data.price + end + local text = '*'..title..'* von *'..developer..'* aus der Kategorie _'..category..'_, durschnittlich bewertet mit '..rating..' Sternen.\n_'..description..'_\n'..installs..' Installationen, Version '..appversion + return text +end + +function play_store:action(msg, config, matches) + local appid = matches[1] + local data = play_store:get_playstore_data(appid) + if data.title == nil then + return + else + utilities.send_reply(self, msg, play_store:send_playstore_data(data), true) + return + end +end + +return play_store