Merge pull request #1 from Brawl345/master
Übernehme änderungen von Brawlbot
This commit is contained in:
commit
5c75429586
35
.travis.yml
Normal file
35
.travis.yml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
language: erlang
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- CURDIR=$(pwd)
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -qq libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev make unzip git libjansson-dev
|
||||||
|
- THIS_DIR=$(cd $(dirname $0); pwd)
|
||||||
|
- cd $THIS_DIR
|
||||||
|
- git clone https://github.com/keplerproject/luarocks.git
|
||||||
|
- cd luarocks
|
||||||
|
- git checkout tags/v2.3.0
|
||||||
|
- PREFIX="$THIS_DIR/.luarocks"
|
||||||
|
- ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config
|
||||||
|
- make build && make install
|
||||||
|
- cd ..
|
||||||
|
- rm -rf luarocks
|
||||||
|
- ./.luarocks/bin/luarocks install luasocket
|
||||||
|
- ./.luarocks/bin/luarocks install luasec
|
||||||
|
- ./.luarocks/bin/luarocks install multipart-post
|
||||||
|
- ./.luarocks/bin/luarocks install dkjson
|
||||||
|
- ./.luarocks/bin/luarocks install oauth
|
||||||
|
- ./.luarocks/bin/luarocks install redis-lua
|
||||||
|
- ./.luarocks/bin/luarocks install lua-cjson
|
||||||
|
- ./.luarocks/bin/luarocks install fakeredis
|
||||||
|
- ./.luarocks/bin/luarocks install xml
|
||||||
|
- ./.luarocks/bin/luarocks install feedparser
|
||||||
|
- ./.luarocks/bin/luarocks install serpent
|
||||||
|
- ./.luarocks/bin/luarocks install sha1
|
||||||
|
- ./.luarocks/bin/luarocks install lpeg
|
||||||
|
- cd $CURDIR
|
||||||
|
|
||||||
|
|
||||||
|
script:
|
||||||
|
- luac -p otouto/*.lua
|
||||||
|
- luac -p otouto/plugins/*.lua
|
29
README.md
29
README.md
@ -1,4 +1,6 @@
|
|||||||
# Brawlbot v2
|
# Brawlbot v2
|
||||||
|
[![Build Status](https://travis-ci.org/Brawl345/Brawlbot-v2.svg?branch=master)](https://travis-ci.org/Brawl345/Brawlbot-v2)
|
||||||
|
|
||||||
The plugin-wielding, multipurpose Telegram bot.
|
The plugin-wielding, multipurpose Telegram bot.
|
||||||
|
|
||||||
[Public Bot](http://telegram.me/mokubot) | [Official Channel](http://telegram.me/otouto) | [Development Group](http://telegram.me/BotDevelopment)
|
[Public Bot](http://telegram.me/mokubot) | [Official Channel](http://telegram.me/otouto) | [Development Group](http://telegram.me/BotDevelopment)
|
||||||
@ -11,11 +13,10 @@ otouto is free software; you are free to redistribute it and/or modify it under
|
|||||||
|
|
||||||
| For Users | For Coders |
|
| For Users | For Coders |
|
||||||
|:----------------------------------------------|:------------------------------|
|
|:----------------------------------------------|:------------------------------|
|
||||||
| [Setup](#setup) | [Introduction](#introduction) |
|
| [Setup](#setup) | [Plugins](#plugins) |
|
||||||
| [Control plugins](#control-plugins) | [Plugins](#plugins) |
|
| [Control plugins](#control-plugins) | [Bindings](#bindings) |
|
||||||
| [Group Administration](#group-administration) | [Bindings](#bindings) |
|
| [Group Administration](#group-administration) | [Output style](#output-style) |
|
||||||
| [List of plugins](#list-of-plugins) | [Output style](#output-style) |
|
| [List of plugins](#list-of-plugins) | [Contributors](#contributors) |
|
||||||
| | [Contributors](#contributors) |
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
You _must_ have Lua (5.2+), luasocket, luasec, multipart-post, and dkjson installed. You should also have lpeg, though it is not required. It is recommended you install these with LuaRocks.
|
You _must_ have Lua (5.2+), luasocket, luasec, multipart-post, and dkjson installed. You should also have lpeg, though it is not required. It is recommended you install these with LuaRocks.
|
||||||
@ -194,9 +195,6 @@ Additionally, antiflood can be configured to automatically ban a user after he h
|
|||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
## Introduction
|
|
||||||
####todo
|
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
otouto uses a robust plugin system, similar to yagop's [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
otouto uses a robust plugin system, similar to yagop's [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
||||||
|
|
||||||
@ -205,13 +203,14 @@ Most plugins are intended for public use, but a few are for other purposes, like
|
|||||||
A plugin can have five components, and two of them are required:
|
A plugin can have five components, and two of them are required:
|
||||||
|
|
||||||
| Component | Description | Required? |
|
| Component | Description | Required? |
|
||||||
|:----------------|:---------------------------------------------|:----------|
|
|:------------------|:---------------------------------------------|:----------|
|
||||||
| plugin:action | Main function. Expects `msg` table as an argument. | Y |
|
| `plugin:action` | Main function. Expects `msg` table as an argument. | Y |
|
||||||
| plugin.triggers | Table of triggers for the plugin. Uses Lua patterns. | Y |
|
| `plugin.triggers` | Table of triggers for the plugin. Uses Lua patterns. | Y |
|
||||||
| plugin:init | Optional function run when the plugin is loaded. | N |
|
| `plugin:init` | Optional function run when the plugin is loaded. | N |
|
||||||
| plugin:cron | Optional function to be called every minute. | N |
|
| `plugin:cron` | Optional function to be called every minute. | N |
|
||||||
| plugin.command | Basic command and syntax. Listed in the help text. | N |
|
| `plugin.command` | Basic command and syntax. Listed in the help text. | N |
|
||||||
| plugin.doc | Usage for the plugin. Returned by "/help $command". | N |
|
| `plugin.doc` | Usage for the plugin. Returned by "/help $command". | N |
|
||||||
|
| `plugin.error` | Plugin-specific error message; false for no message. | N |
|
||||||
|
|
||||||
The `bot:on_msg_receive` function adds a few variables to the `msg` table for your convenience. These are self-explanatory: `msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
The `bot:on_msg_receive` function adds a few variables to the `msg` table for your convenience. These are self-explanatory: `msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ Sende /hilfe, um zu starten
|
|||||||
cmd_pat = '/',
|
cmd_pat = '/',
|
||||||
|
|
||||||
errors = { -- Generic error messages used in various plugins.
|
errors = { -- Generic error messages used in various plugins.
|
||||||
|
generic = 'An unexpected error occurred.',
|
||||||
connection = 'Verbindungsfehler.',
|
connection = 'Verbindungsfehler.',
|
||||||
quotaexceeded = 'API-Quota aufgebraucht.',
|
quotaexceeded = 'API-Quota aufgebraucht.',
|
||||||
results = 'Keine Ergebnisse gefunden.',
|
results = 'Keine Ergebnisse gefunden.',
|
||||||
@ -30,7 +31,7 @@ Sende /hilfe, um zu starten
|
|||||||
syntax = 'Invalide Syntax.',
|
syntax = 'Invalide Syntax.',
|
||||||
chatter_connection = 'Ich möchte gerade nicht reden',
|
chatter_connection = 'Ich möchte gerade nicht reden',
|
||||||
chatter_response = 'Ich weiß nicht, was ich darauf antworten soll.'
|
chatter_response = 'Ich weiß nicht, was ich darauf antworten soll.'
|
||||||
},
|
}
|
||||||
|
|
||||||
plugins = { -- To enable a plugin, add its name to the list.
|
plugins = { -- To enable a plugin, add its name to the list.
|
||||||
'control',
|
'control',
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package = 'otouto'
|
|
||||||
version = 'dev-1'
|
|
||||||
|
|
||||||
source = {
|
|
||||||
url = 'git://github.com/topkecleon/otouto.git'
|
|
||||||
}
|
|
||||||
|
|
||||||
description = {
|
|
||||||
summary = 'The plugin-wielding, multipurpose Telegram bot!',
|
|
||||||
detailed = 'A plugin-wielding, multipurpose bot for the Telegram API.',
|
|
||||||
homepage = 'http://otou.to',
|
|
||||||
maintainer = 'Drew <drew@otou.to>',
|
|
||||||
license = 'GPL-2'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies = {
|
|
||||||
'lua >= 5.2',
|
|
||||||
'LuaSocket ~> 3.0',
|
|
||||||
'LuaSec ~> 0.6',
|
|
||||||
'dkjson ~> 2.5',
|
|
||||||
'LPeg ~> 1.0'
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ local bindings -- Load Telegram bindings.
|
|||||||
local utilities -- Load miscellaneous and cross-plugin functions.
|
local utilities -- Load miscellaneous and cross-plugin functions.
|
||||||
local redis = (loadfile "./otouto/redis.lua")()
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
bot.version = '2'
|
bot.version = '2.0'
|
||||||
|
|
||||||
function bot:init(config) -- The function run when the bot is started or reloaded.
|
function bot:init(config) -- The function run when the bot is started or reloaded.
|
||||||
|
|
||||||
@ -69,14 +69,28 @@ function bot:on_msg_receive(msg, config) -- The fn run whenever a message is rec
|
|||||||
msg.text_lower = msg.text:lower()
|
msg.text_lower = msg.text:lower()
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,v in ipairs(self.plugins) do
|
for _, plugin in ipairs(self.plugins) do
|
||||||
for _,w in pairs(v.triggers) do
|
for _, trigger in pairs(plugin.triggers) do
|
||||||
if string.match(msg.text_lower, w) then
|
if string.match(msg.text_lower, trigger) then
|
||||||
local success, result = pcall(function()
|
local success, result = pcall(function()
|
||||||
return v.action(self, msg, config)
|
-- trying to port matches to otouto
|
||||||
|
for k, pattern in pairs(plugin.triggers) do
|
||||||
|
matches = match_pattern(pattern, msg.text)
|
||||||
|
if matches then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return plugin.action(self, msg, config, matches)
|
||||||
end)
|
end)
|
||||||
if not success then
|
if not success then
|
||||||
utilities.send_reply(self, msg, 'Sorry, an unexpected error occurred.')
|
-- If the plugin has an error message, send it. If it does
|
||||||
|
-- not, use the generic one specified in config. If it's set
|
||||||
|
-- to false, do nothing.
|
||||||
|
if plugin.error then
|
||||||
|
utilities.send_reply(self, msg, plugin.error)
|
||||||
|
elseif plugin.error == nil then
|
||||||
|
utilities.send_reply(self, msg, config.errors.generic, true)
|
||||||
|
end
|
||||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -26,6 +26,7 @@ function ninegag:get_9GAG()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ninegag:action(msg, config)
|
function ninegag:action(msg, config)
|
||||||
|
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||||
local url, title = ninegag:get_9GAG()
|
local url, title = ninegag:get_9GAG()
|
||||||
if not url then
|
if not url then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
@ -33,9 +34,7 @@ function ninegag:action(msg, config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local file = download_to_file(url)
|
local file = download_to_file(url)
|
||||||
bindings.sendPhoto(self, {chat_id = msg.chat.id, caption = title}, {photo = file} )
|
utilities.send_photo(self, msg.chat.id, file, title)
|
||||||
os.remove(file)
|
|
||||||
print("Deleted: "..file)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return ninegag
|
return ninegag
|
||||||
|
@ -71,6 +71,9 @@ function administration:init(config)
|
|||||||
|
|
||||||
administration.doc = '`Returns a list of administrated groups.\nUse '..config.cmd_pat..'ahelp for more administrative commands.`'
|
administration.doc = '`Returns a list of administrated groups.\nUse '..config.cmd_pat..'ahelp for more administrative commands.`'
|
||||||
|
|
||||||
|
-- In the worst case, don't send errors in reply to random messages.
|
||||||
|
administration.error = false
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function administration.init_flags(cmd_pat) return {
|
function administration.init_flags(cmd_pat) return {
|
||||||
@ -265,7 +268,7 @@ function administration:kick_user(chat, target, reason, config)
|
|||||||
victim = utilities.build_name(
|
victim = utilities.build_name(
|
||||||
self.database.users[tostring(target)].first_name,
|
self.database.users[tostring(target)].first_name,
|
||||||
self.database.users[tostring(target)].last_name
|
self.database.users[tostring(target)].last_name
|
||||||
)
|
) .. ' [' .. victim .. ']'
|
||||||
end
|
end
|
||||||
local group = self.database.administration.groups[tostring(chat)].name
|
local group = self.database.administration.groups[tostring(chat)].name
|
||||||
utilities.handle_exception(self, victim..' kicked from '..group, reason, config)
|
utilities.handle_exception(self, victim..' kicked from '..group, reason, config)
|
||||||
@ -917,7 +920,9 @@ function administration.init_command(self_, config)
|
|||||||
if input then
|
if input then
|
||||||
input = utilities.get_word(input, 1)
|
input = utilities.get_word(input, 1)
|
||||||
input = tonumber(input)
|
input = tonumber(input)
|
||||||
if not input or not administration.flags[input] then input = false end
|
if not input or not administration.flags[input] then
|
||||||
|
input = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if not input then
|
if not input then
|
||||||
local output = '*Flags for ' .. msg.chat.title .. ':*\n'
|
local output = '*Flags for ' .. msg.chat.title .. ':*\n'
|
||||||
@ -1209,7 +1214,9 @@ function administration.init_command(self_, config)
|
|||||||
doc = 'Adds a group to the administration system. Pass numbers as arguments to enable those flags immediately. For example, this would add the group and enable the unlisted flag, antibot, and antiflood:\n/gadd 1 4 5',
|
doc = 'Adds a group to the administration system. Pass numbers as arguments to enable those flags immediately. For example, this would add the group and enable the unlisted flag, antibot, and antiflood:\n/gadd 1 4 5',
|
||||||
|
|
||||||
action = function(self, msg, group, config)
|
action = function(self, msg, group, config)
|
||||||
if self.database.administration.groups[msg.chat.id_str] then
|
if msg.chat.id == msg.from.id then
|
||||||
|
utilities.send_message(self, msg.chat.id, 'No.')
|
||||||
|
elseif self.database.administration.groups[msg.chat.id_str] then
|
||||||
utilities.send_reply(self, msg, 'I am already administrating this group.')
|
utilities.send_reply(self, msg, 'I am already administrating this group.')
|
||||||
else
|
else
|
||||||
local flags = {}
|
local flags = {}
|
||||||
@ -1327,6 +1334,18 @@ function administration.init_command(self_, config)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
},
|
||||||
|
|
||||||
|
{ -- /buildwall :^)
|
||||||
|
triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('buildwall').table,
|
||||||
|
privilege = 3,
|
||||||
|
interior = true,
|
||||||
|
action = function(self, msg, group, config)
|
||||||
|
for i = 2, 5 do
|
||||||
|
group.flags[i] = true
|
||||||
|
end
|
||||||
|
utilities.send_message(self, msg.chat.id, 'antisquig, antisquig++, antibot, and antiflood have been enabled.')
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
117
otouto/plugins/app_store.lua
Normal file
117
otouto/plugins/app_store.lua
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
local app_store = {}
|
||||||
|
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
app_store.triggers = {
|
||||||
|
"itunes.apple.com/(.*)/app/(.*)/id(%d+)",
|
||||||
|
"^!itunes (%d+)$",
|
||||||
|
"itunes.apple.com/app/id(%d+)"
|
||||||
|
}
|
||||||
|
|
||||||
|
local BASE_URL = 'https://itunes.apple.com/lookup'
|
||||||
|
|
||||||
|
local makeOurDate = function(dateString)
|
||||||
|
local pattern = "(%d+)%-(%d+)%-(%d+)T"
|
||||||
|
local year, month, day = dateString:match(pattern)
|
||||||
|
return day..'.'..month..'.'..year
|
||||||
|
end
|
||||||
|
|
||||||
|
function app_store:get_appstore_data()
|
||||||
|
local url = BASE_URL..'/?id='..appid..'&country=de'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return "HTTP-FEHLER" end
|
||||||
|
local data = json.decode(res).results[1]
|
||||||
|
|
||||||
|
if data == nil then return 'NOTFOUND' end
|
||||||
|
if data.wrapperType ~= 'software' then return nil end
|
||||||
|
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function app_store:send_appstore_data(data)
|
||||||
|
-- Header
|
||||||
|
local name = data.trackName
|
||||||
|
local author = data.sellerName
|
||||||
|
local price = data.formattedPrice
|
||||||
|
local version = data.version
|
||||||
|
|
||||||
|
-- Body
|
||||||
|
local description = string.sub(unescape(data.description), 1, 150) .. '...'
|
||||||
|
local min_ios_ver = data.minimumOsVersion
|
||||||
|
local size = string.gsub(round(data.fileSizeBytes / 1000000, 2), "%.", ",") -- wtf Apple, it's 1024, not 1000!
|
||||||
|
local release = makeOurDate(data.releaseDate)
|
||||||
|
if data.isGameCenterEnabled then
|
||||||
|
game_center = '\nUnterstützt Game Center'
|
||||||
|
else
|
||||||
|
game_center = ''
|
||||||
|
end
|
||||||
|
local category_count = tablelength(data.genres)
|
||||||
|
if category_count == 1 then
|
||||||
|
category = '\nKategorie: '..data.genres[1]
|
||||||
|
else
|
||||||
|
local category_loop = '\nKategorien: '
|
||||||
|
for v in pairs(data.genres) do
|
||||||
|
if v < category_count then
|
||||||
|
category_loop = category_loop..data.genres[v]..', '
|
||||||
|
else
|
||||||
|
category_loop = category_loop..data.genres[v]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
category = category_loop
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Footer
|
||||||
|
if data.averageUserRating and data.userRatingCount then
|
||||||
|
avg_rating = 'Bewertung: '..string.gsub(data.averageUserRating, "%.", ",")..' Sterne '
|
||||||
|
ratings = 'von '..comma_value(data.userRatingCount)..' Bewertungen'
|
||||||
|
else
|
||||||
|
avg_rating = ""
|
||||||
|
ratings = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local header = '*'..name..'* v'..version..' von *'..author..'* ('..price..'):'
|
||||||
|
local body = '\n'..description..'\n_Benötigt mind. iOS '..min_ios_ver..'_\nGröße: '..size..' MB\nErstveröffentlicht am '..release..game_center..category
|
||||||
|
local footer = '\n'..avg_rating..ratings
|
||||||
|
local text = header..body..footer
|
||||||
|
|
||||||
|
-- Picture
|
||||||
|
if data.screenshotUrls[1] and data.ipadScreenshotUrls[1] then
|
||||||
|
image_url = data.screenshotUrls[1]
|
||||||
|
elseif data.screenshotUrls[1] and not data.ipadScreenshotUrls[1] then
|
||||||
|
image_url = data.screenshotUrls[1]
|
||||||
|
elseif not data.screenshotUrls[1] and data.ipadScreenshotUrls[1] then
|
||||||
|
image_url = data.ipadScreenshotUrls[1]
|
||||||
|
else
|
||||||
|
image_url = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return text, image_url
|
||||||
|
end
|
||||||
|
|
||||||
|
function app_store:action(msg, config, matches)
|
||||||
|
if not matches[3] then
|
||||||
|
appid = matches[1]
|
||||||
|
else
|
||||||
|
appid = matches[3]
|
||||||
|
end
|
||||||
|
local data = app_store:get_appstore_data()
|
||||||
|
if data == nil then print('Das Appstore-Plugin unterstützt nur Apps!') end
|
||||||
|
if data == 'HTTP-FEHLER' or data == 'NOTFOUND' then
|
||||||
|
utilities.send_reply(self, msg, '*App nicht gefunden!*', true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
local output, image_url = app_store:send_appstore_data(data)
|
||||||
|
utilities.send_reply(self, msg, output, true)
|
||||||
|
if image_url then
|
||||||
|
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||||
|
local file = download_to_file(image_url)
|
||||||
|
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return app_store
|
48
otouto/plugins/bitly.lua
Normal file
48
otouto/plugins/bitly.lua
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
local bitly = {}
|
||||||
|
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function bitly:init(config)
|
||||||
|
if not cred_data.bitly_access_token then
|
||||||
|
print('Missing config value: bitly_access_token.')
|
||||||
|
print('bitly.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
bitly.triggers = {
|
||||||
|
"bit.ly/([A-Za-z0-9-_-]+)",
|
||||||
|
"bitly.com/([A-Za-z0-9-_-]+)",
|
||||||
|
"j.mp/([A-Za-z0-9-_-]+)",
|
||||||
|
"andib.tk/([A-Za-z0-9-_-]+)"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local BASE_URL = 'https://api-ssl.bitly.com/v3/expand'
|
||||||
|
|
||||||
|
function bitly:expand_bitly_link (shorturl)
|
||||||
|
local access_token = cred_data.bitly_access_token
|
||||||
|
local url = BASE_URL..'?access_token='..access_token..'&shortUrl=https://bit.ly/'..shorturl
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return "HTTP-FEHLER" end
|
||||||
|
local data = json.decode(res).data.expand[1]
|
||||||
|
cache_data('bitly', shorturl, data)
|
||||||
|
return data.long_url
|
||||||
|
end
|
||||||
|
|
||||||
|
function bitly:action(msg, config, matches)
|
||||||
|
local shorturl = matches[1]
|
||||||
|
local hash = 'telegram:cache:bitly:'..shorturl
|
||||||
|
if redis:exists(hash) == false then
|
||||||
|
utilities.send_reply(self, msg, bitly:expand_bitly_link(shorturl))
|
||||||
|
return
|
||||||
|
else
|
||||||
|
local data = redis:hgetall(hash)
|
||||||
|
utilities.send_reply(self, msg, data.long_url)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return bitly
|
142
otouto/plugins/bitly_create.lua
Normal file
142
otouto/plugins/bitly_create.lua
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
local bitly_create = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local OAuth = require "OAuth"
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function bitly_create:init(config)
|
||||||
|
if not cred_data.bitly_client_id then
|
||||||
|
print('Missing config value: bitly_client_id.')
|
||||||
|
print('bitly_create.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
elseif not cred_data.bitly_client_secret then
|
||||||
|
print('Missing config value: bitly_client_secret.')
|
||||||
|
print('bitly_create.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
elseif not cred_data.bitly_redirect_uri then
|
||||||
|
print('Missing config value: bitly_redirect_uri.')
|
||||||
|
print('bitly_create.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
bitly_create.triggers = {
|
||||||
|
"^/short (auth) (.+)$",
|
||||||
|
"^/short (auth)$",
|
||||||
|
"^/short (unauth)$",
|
||||||
|
"^/short (me)$",
|
||||||
|
"^/short (j.mp) (https?://[%w-_%.%?%.:/%+=&]+)$",
|
||||||
|
"^/short (bit.ly) (https?://[%w-_%.%?%.:/%+=&]+)$",
|
||||||
|
"^/short (bitly.com) (https?://[%w-_%.%?%.:/%+=&]+)$",
|
||||||
|
"^/short (https?://[%w-_%.%?%.:/%+=&]+)$"
|
||||||
|
}
|
||||||
|
bitly_create.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[short* _<Link>_: Kürzt einen Link mit der Standard Bitly-Adresse
|
||||||
|
*]]..config.cmd_pat..[[short* _<j.mp|bit.ly|bitly.com>_ _[Link]_: Kürzt einen Link mit der ausgewählten Kurz-URL
|
||||||
|
*]]..config.cmd_pat..[[short* _auth_: Loggt deinen Account ein und nutzt ihn für deine Links (empfohlen!)
|
||||||
|
*]]..config.cmd_pat..[[short* _me_: Gibt den eingeloggten Account aus
|
||||||
|
*]]..config.cmd_pat..[[short* _unauth_: Loggt deinen Account aus
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
bitly_create.command = 'short <URL>'
|
||||||
|
|
||||||
|
local BASE_URL = 'https://api-ssl.bitly.com'
|
||||||
|
|
||||||
|
local client_id = cred_data.bitly_client_id
|
||||||
|
local client_secret = cred_data.bitly_client_secret
|
||||||
|
local redirect_uri = cred_data.bitly_redirect_uri
|
||||||
|
|
||||||
|
function bitly_create:get_bitly_access_token(hash, code)
|
||||||
|
local req = post_petition(BASE_URL..'/oauth/access_token', 'client_id='..client_id..'&client_secret='..client_secret..'&code='..code..'&redirect_uri='..redirect_uri)
|
||||||
|
if not req.access_token then return '*Fehler beim Einloggen!*' end
|
||||||
|
|
||||||
|
local access_token = req.access_token
|
||||||
|
local login_name = req.login
|
||||||
|
redis:hset(hash, 'bitly', access_token)
|
||||||
|
return 'Erfolgreich als `'..login_name..'` eingeloggt!'
|
||||||
|
end
|
||||||
|
|
||||||
|
function bitly_create:get_bitly_user_info(bitly_access_token)
|
||||||
|
local url = BASE_URL..'/v3/user/info?access_token='..bitly_access_token..'&format=json'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code == 401 then return 'Login fehlgeschlagen!' end
|
||||||
|
if code ~= 200 then return 'HTTP-Fehler!' end
|
||||||
|
|
||||||
|
local data = json.decode(res).data
|
||||||
|
|
||||||
|
if data.full_name then
|
||||||
|
name = '*'..data.full_name..'* (`'..data.login..'`)'
|
||||||
|
else
|
||||||
|
name = '`'..data.login..'`'
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = 'Eingeloggt als '..name
|
||||||
|
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function bitly_create:create_bitlink (long_url, domain, bitly_access_atoken)
|
||||||
|
local url = BASE_URL..'/v3/shorten?access_token='..bitly_access_token..'&domain='..domain..'&longUrl='..long_url..'&format=txt'
|
||||||
|
local text,code = https.request(url)
|
||||||
|
if code ~= 200 then return 'FEHLER: '..text end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function bitly_create:action(msg, config, matches)
|
||||||
|
local hash = 'user:'..msg.from.id
|
||||||
|
bitly_access_token = redis:hget(hash, 'bitly')
|
||||||
|
|
||||||
|
if matches[1] == 'auth' and matches[2] then
|
||||||
|
utilities.send_reply(self, msg, bitly_create:get_bitly_access_token(hash, matches[2]), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'auth' then
|
||||||
|
utilities.send_reply(self, msg, 'Bitte logge dich ein und folge den Anweisungen:\n[Bei Bitly anmelden](https://bitly.com/oauth/authorize?client_id='..client_id..'&redirect_uri='..redirect_uri..')', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'unauth' and bitly_access_token then
|
||||||
|
redis:hdel(hash, 'bitly')
|
||||||
|
utilities.send_reply(self, msg, '*Erfolgreich ausgeloggt!* Du kannst den Zugriff [in deinen Kontoeinstellungen](https://bitly.com/a/settings/connected) endgültig entziehen.', true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == 'unauth' and not bitly_access_token then
|
||||||
|
utilities.send_reply(self, msg, 'Wie willst du dich ausloggen, wenn du gar nicht eingeloggt bist?', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'me' and bitly_access_token then
|
||||||
|
local text = bitly_create:get_bitly_user_info(bitly_access_token)
|
||||||
|
if text then
|
||||||
|
utilities.send_reply(self, msg, text, true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
elseif matches[1] == 'me' and not bitly_access_token then
|
||||||
|
utilities.send_reply(self, msg, 'Du bist nicht eingeloggt! Logge dich ein mit\n/short auth', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not bitly_access_token then
|
||||||
|
print('Not signed in, will use global bitly access_token')
|
||||||
|
bitly_access_token = cred_data.bitly_access_token
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[2] == nil then
|
||||||
|
long_url = url_encode(matches[1])
|
||||||
|
domain = 'bit.ly'
|
||||||
|
else
|
||||||
|
long_url = url_encode(matches[2])
|
||||||
|
domain = matches[1]
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, bitly_create:create_bitlink(long_url, domain, bitly_access_token))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return bitly_create
|
125
otouto/plugins/creds.lua
Normal file
125
otouto/plugins/creds.lua
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
local creds_manager = {}
|
||||||
|
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function creds_manager:init(config)
|
||||||
|
creds_manager.triggers = {
|
||||||
|
"^(/creds)$",
|
||||||
|
"^(/creds add) ([^%s]+) (.+)$",
|
||||||
|
"^(/creds del) (.+)$",
|
||||||
|
"^(/creds rename) ([^%s]+) (.+)$"
|
||||||
|
}
|
||||||
|
creds_manager.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[creds*: Zeigt alle Logindaten und API-Keys
|
||||||
|
*]]..config.cmd_pat..[[creds* _add_ _<Variable>_ _<Schlüssel>_: Speichert Schlüssel mit dieser Variable ein
|
||||||
|
*]]..config.cmd_pat..[[creds* _del_ _<Variable>_: Löscht Schlüssel mit dieser Variable
|
||||||
|
*]]..config.cmd_pat..[[creds* _rename_ _<Variable>_ _<Neue Variable>_: Benennt Variable um, behält Schlüssel bei
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
creds_manager.command = 'creds'
|
||||||
|
|
||||||
|
local hash = "telegram:credentials"
|
||||||
|
|
||||||
|
-- See: http://www.lua.org/pil/19.3.html
|
||||||
|
function pairsByKeys (t, f)
|
||||||
|
local a = {}
|
||||||
|
for n in pairs(t) do table.insert(a, n) end
|
||||||
|
table.sort(a, f)
|
||||||
|
local i = 0 -- iterator variable
|
||||||
|
local iter = function () -- iterator function
|
||||||
|
i = i + 1
|
||||||
|
if a[i] == nil then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return a[i], t[a[i]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return iter
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:reload_creds()
|
||||||
|
cred_data = redis:hgetall(hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:list_creds()
|
||||||
|
creds_manager:reload_creds()
|
||||||
|
if redis:exists("telegram:credentials") == true then
|
||||||
|
local text = ""
|
||||||
|
for var, key in pairsByKeys(cred_data) do
|
||||||
|
text = text..var..' = '..key..'\n'
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
else
|
||||||
|
create_cred()
|
||||||
|
return "Es wurden noch keine Logininformationen gespeichert, lege Tabelle an...\nSpeichere Keys mit /creds add [Variable] [Key] ein!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:add_creds(var, key)
|
||||||
|
print('Saving credential for '..var..' to redis hash '..hash)
|
||||||
|
redis:hset(hash, var, key)
|
||||||
|
creds_manager:reload_creds()
|
||||||
|
return 'Gespeichert!'
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:del_creds(var)
|
||||||
|
if redis:hexists(hash, var) == true then
|
||||||
|
print('Deleting credential for '..var..' from redis hash '..hash)
|
||||||
|
redis:hdel(hash, var)
|
||||||
|
creds_manager:reload_creds()
|
||||||
|
return 'Key von "'..var..'" erfolgreich gelöscht!'
|
||||||
|
else
|
||||||
|
return 'Du hast keine Logininformationen für diese Variable eingespeichert.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:rename_creds(var, newvar)
|
||||||
|
if redis:hexists(hash, var) == true then
|
||||||
|
local key = redis:hget(hash, var)
|
||||||
|
if redis:hsetnx(hash, newvar, key) == true then
|
||||||
|
redis:hdel(hash, var)
|
||||||
|
creds_manager:reload_creds()
|
||||||
|
return '"'..var..'" erfolgreich zu "'..newvar..'" umbenannt.'
|
||||||
|
else
|
||||||
|
return "Variable konnte nicht umbenannt werden: Zielvariable existiert bereits."
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return 'Die zu umbennende Variable existiert nicht.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function creds_manager:action(msg, config, matches)
|
||||||
|
local receiver = msg.from.id
|
||||||
|
if receiver ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if msg.chat.type ~= 'private' then
|
||||||
|
utilities.send_reply(self, msg, 'Dieses Plugin solltest du nur [privat](http://telegram.me/' .. self.info.username .. '?start=creds) verwenden!', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == "/creds" then
|
||||||
|
utilities.send_reply(self, msg, creds_manager:list_creds())
|
||||||
|
return
|
||||||
|
elseif matches[1] == "/creds add" then
|
||||||
|
local var = string.lower(string.sub(matches[2], 1, 50))
|
||||||
|
local key = string.sub(matches[3], 1, 1000)
|
||||||
|
utilities.send_reply(self, msg, creds_manager:add_creds(var, key))
|
||||||
|
return
|
||||||
|
elseif matches[1] == "/creds del" then
|
||||||
|
local var = string.lower(matches[2])
|
||||||
|
utilities.send_reply(self, msg, creds_manager:del_creds(var))
|
||||||
|
return
|
||||||
|
elseif matches[1] == "/creds rename" then
|
||||||
|
local var = string.lower(string.sub(matches[2], 1, 50))
|
||||||
|
local newvar = string.lower(string.sub(matches[3], 1, 1000))
|
||||||
|
utilities.send_reply(self, msg, creds_manager:rename_creds(var, newvar))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return creds_manager
|
@ -1,56 +0,0 @@
|
|||||||
local dice = {}
|
|
||||||
|
|
||||||
local utilities = require('otouto.utilities')
|
|
||||||
|
|
||||||
dice.command = 'roll <nDr>'
|
|
||||||
|
|
||||||
function dice:init(config)
|
|
||||||
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
|
||||||
dice.doc = [[```
|
|
||||||
]]..config.cmd_pat..[[roll <nDr>
|
|
||||||
Returns a set of dice rolls, where n is the number of rolls and r is the range. If only a range is given, returns only one roll.
|
|
||||||
```]]
|
|
||||||
end
|
|
||||||
|
|
||||||
function dice:action(msg)
|
|
||||||
|
|
||||||
local input = utilities.input(msg.text_lower)
|
|
||||||
if not input then
|
|
||||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local count, range
|
|
||||||
if input:match('^[%d]+d[%d]+$') then
|
|
||||||
count, range = input:match('([%d]+)d([%d]+)')
|
|
||||||
elseif input:match('^d?[%d]+$') then
|
|
||||||
count = 1
|
|
||||||
range = input:match('^d?([%d]+)$')
|
|
||||||
else
|
|
||||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
count = tonumber(count)
|
|
||||||
range = tonumber(range)
|
|
||||||
|
|
||||||
if range < 2 then
|
|
||||||
utilities.send_reply(self, msg, 'The minimum range is 2.')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if range > 1000 or count > 1000 then
|
|
||||||
utilities.send_reply(self, msg, 'The maximum range and count are 1000.')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local output = '*' .. count .. 'd' .. range .. '*\n`'
|
|
||||||
for _ = 1, count do
|
|
||||||
output = output .. math.random(range) .. '\t'
|
|
||||||
end
|
|
||||||
output = output .. '`'
|
|
||||||
|
|
||||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return dice
|
|
37
otouto/plugins/expand.lua
Normal file
37
otouto/plugins/expand.lua
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
local expand = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
|
function expand:init(config)
|
||||||
|
expand.triggers = {
|
||||||
|
"^/expand (https?://[%w-_%.%?%.:/%+=&]+)$"
|
||||||
|
}
|
||||||
|
|
||||||
|
expand.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[expand* _<Kurz-URL>_: Verlängert Kurz-URL (301er/302er)]]
|
||||||
|
end
|
||||||
|
|
||||||
|
expand.command = 'expand <Kurz-URL>'
|
||||||
|
|
||||||
|
function expand:action(msg, config, matches)
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = matches[1],
|
||||||
|
method = "HEAD",
|
||||||
|
sink = ltn12.sink.table(response_body),
|
||||||
|
headers = {},
|
||||||
|
redirect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local ok, response_code, response_headers, response_status_line = http.request(request_constructor)
|
||||||
|
if ok and response_headers.location then
|
||||||
|
utilities.send_reply(self, msg, response_headers.location)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, "Fehler beim Erweitern der URL.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return expand
|
180
otouto/plugins/facebook.lua
Normal file
180
otouto/plugins/facebook.lua
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
local facebook = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function facebook:init(config)
|
||||||
|
if not cred_data.fb_access_token then
|
||||||
|
print('Missing config value: fb_access_token.')
|
||||||
|
print('facebook.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
facebook.triggers = {
|
||||||
|
"facebook.com/([A-Za-z0-9-._-]+)/(posts)/(%d+)",
|
||||||
|
"facebook.com/(permalink).php%?(story_fbid)=(%d+)&id=(%d+)",
|
||||||
|
"facebook.com/(photo).php%?fbid=(%d+)",
|
||||||
|
"facebook.com/([A-Za-z0-9-._-]+)/(photos)/a.(%d+[%d%.]*)/(%d+)",
|
||||||
|
"facebook.com/(video).php%?v=(%d+)",
|
||||||
|
"facebook.com/([A-Za-z0-9-._-]+)/(videos)/(%d+[%d%.]*)",
|
||||||
|
"facebook.com/([A-Za-z0-9-._-]+)"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local BASE_URL = 'https://graph.facebook.com/v2.5'
|
||||||
|
local fb_access_token = cred_data.fb_access_token
|
||||||
|
|
||||||
|
local makeOurDate = function(dateString)
|
||||||
|
local pattern = "(%d+)%/(%d+)%/(%d+)"
|
||||||
|
local month, day, year = dateString:match(pattern)
|
||||||
|
return day..'.'..month..'.'..year
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:get_fb_id(name)
|
||||||
|
local url = BASE_URL..'/'..name..'?access_token='..fb_access_token..'&locale=de_DE'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
local data = json.decode(res)
|
||||||
|
return data.id
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:fb_post (id, story_id)
|
||||||
|
local url = BASE_URL..'/'..id..'_'..story_id..'?access_token='..fb_access_token..'&locale=de_DE&fields=from,name,story,message,link'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
local data = json.decode(res)
|
||||||
|
|
||||||
|
local from = data.from.name
|
||||||
|
local message = data.message
|
||||||
|
local name = data.name
|
||||||
|
if data.link then
|
||||||
|
link = '\n'..data.name..':\n'..data.link
|
||||||
|
else
|
||||||
|
link = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.story then
|
||||||
|
story = ' ('..data.story..')'
|
||||||
|
else
|
||||||
|
story = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = '*'..from..'*'..story..':\n'..message..'\n'..link
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:send_facebook_photo(photo_id, receiver)
|
||||||
|
local url = BASE_URL..'/'..photo_id..'?access_token='..fb_access_token..'&locale=de_DE&fields=images,from,name'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
local data = json.decode(res)
|
||||||
|
|
||||||
|
local from = '*'..data.from.name..'*'
|
||||||
|
if data.name then
|
||||||
|
text = from..' hat ein Bild gepostet:\n'..data.name
|
||||||
|
else
|
||||||
|
text = from..' hat ein Bild gepostet:'
|
||||||
|
end
|
||||||
|
local image_url = data.images[1].source
|
||||||
|
return text, image_url
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:send_facebook_video(video_id)
|
||||||
|
local url = BASE_URL..'/'..video_id..'?access_token='..fb_access_token..'&locale=de_DE&fields=description,from,source,title'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
local data = json.decode(res)
|
||||||
|
|
||||||
|
local from = '*'..data.from.name..'*'
|
||||||
|
local description = data.description
|
||||||
|
local source = data.source
|
||||||
|
if data.title then
|
||||||
|
text = from..' hat ein Video gepostet:\n'..description..'\n['..data.title..']('..source..')'
|
||||||
|
else
|
||||||
|
text = from..' hat ein Video gepostet:\n'..description..'\n'..utilities.md_escape(source)
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:facebook_info(name)
|
||||||
|
local url = BASE_URL..'/'..name..'?access_token='..fb_access_token..'&locale=de_DE&fields=about,name,birthday,category,founded,general_info,is_verified'
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
local data = json.decode(res)
|
||||||
|
|
||||||
|
local name = data.name
|
||||||
|
if data.is_verified then
|
||||||
|
name = name..' ✅'
|
||||||
|
end
|
||||||
|
|
||||||
|
local category = data.category
|
||||||
|
|
||||||
|
if data.about then
|
||||||
|
about = '\n'..data.about
|
||||||
|
else
|
||||||
|
about = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.general_info then
|
||||||
|
general_info = '\n'..data.general_info
|
||||||
|
else
|
||||||
|
general_info = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.birthday and data.founded then
|
||||||
|
birth = '\nGeburtstag: '..makeOurDate(data.birthday)
|
||||||
|
elseif data.birthday and not data.founded then
|
||||||
|
birth = '\nGeburtstag: '..makeOurDate(data.birthday)
|
||||||
|
elseif data.founded and not data.birthday then
|
||||||
|
birth = '\nGegründet: '..data.founded
|
||||||
|
else
|
||||||
|
birth = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = '*'..name..'* ('..category..')_'..about..'_'..general_info..birth
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function facebook:action(msg, config, matches)
|
||||||
|
if matches[1] == 'permalink' or matches[2] == 'posts' then
|
||||||
|
story_id = matches[3]
|
||||||
|
if not matches[4] then
|
||||||
|
id = facebook:get_fb_id(matches[1])
|
||||||
|
else
|
||||||
|
id = matches[4]
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, facebook:fb_post(id, story_id), true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == 'photo' or matches[2] == 'photos' then
|
||||||
|
if not matches[4] then
|
||||||
|
photo_id = matches[2]
|
||||||
|
else
|
||||||
|
photo_id = matches[4]
|
||||||
|
end
|
||||||
|
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||||
|
local text, image_url = facebook:send_facebook_photo(photo_id, receiver)
|
||||||
|
local file = download_to_file(image_url)
|
||||||
|
utilities.send_reply(self, msg, text, true)
|
||||||
|
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
elseif matches[1] == 'video' or matches[2] == 'videos' then
|
||||||
|
if not matches[3] then
|
||||||
|
video_id = matches[2]
|
||||||
|
else
|
||||||
|
video_id = matches[3]
|
||||||
|
end
|
||||||
|
local output = facebook:send_facebook_video(video_id)
|
||||||
|
utilities.send_reply(self, msg, output, true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, facebook:facebook_info(matches[1]), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return facebook
|
222
otouto/plugins/forecast.lua
Normal file
222
otouto/plugins/forecast.lua
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
local forecast = {}
|
||||||
|
|
||||||
|
local HTTPS = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
|
local JSON = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function forecast:init(config)
|
||||||
|
if not cred_data.forecastio_apikey then
|
||||||
|
print('Missing config value: forecastio_apikey.')
|
||||||
|
print('weather.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
elseif not cred_data.google_apikey then
|
||||||
|
print('Missing config value: google_apikey.')
|
||||||
|
print('weather.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
forecast.triggers = {
|
||||||
|
"^(/f)$",
|
||||||
|
"^(/f) (.*)$",
|
||||||
|
"^(/fh)$",
|
||||||
|
"^(/fh) (.*)$",
|
||||||
|
"^(/forecast)$",
|
||||||
|
"^(/forecast) (.*)$",
|
||||||
|
"^(/forecasth)$",
|
||||||
|
"^(/forecasth) (.*)$"
|
||||||
|
}
|
||||||
|
forecast.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[f*: Wettervorhersage für deinen Wohnort _(/location set <Ort>)_
|
||||||
|
*]]..config.cmd_pat..[[f* _<Ort>_: Wettervorhersage für diesen Ort
|
||||||
|
*]]..config.cmd_pat..[[fh*: 24-Stunden-Wettervorhersage für deine Stadt _(/location set [Ort]_
|
||||||
|
*]]..config.cmd_pat..[[fh* _<Ort>_: 24-Stunden-Wettervorhersage für diesen Ort
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
forecast.command = 'forecast'
|
||||||
|
|
||||||
|
local BASE_URL = "https://api.forecast.io/forecast"
|
||||||
|
local apikey = cred_data.forecastio_apikey
|
||||||
|
local google_apikey = cred_data.google_apikey
|
||||||
|
|
||||||
|
function get_city_name(lat, lng)
|
||||||
|
local city = redis:hget('telegram:cache:weather:pretty_names', lat..','..lng)
|
||||||
|
if city then return city end
|
||||||
|
local url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='..lat..','..lng..'&result_type=political&language=de&key='..google_apikey
|
||||||
|
local res, code = HTTPS.request(url)
|
||||||
|
if code ~= 200 then return 'Unbekannte Stadt' end
|
||||||
|
local data = JSON.decode(res).results[1]
|
||||||
|
local city = data.formatted_address
|
||||||
|
print('Setting '..lat..','..lng..' in redis hash telegram:cache:weather:pretty_names to "'..city..'"')
|
||||||
|
redis:hset('telegram:cache:weather:pretty_names', lat..','..lng, city)
|
||||||
|
return city
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_condition_symbol(weather, n)
|
||||||
|
if weather.data[n].icon == 'clear-day' then
|
||||||
|
return '☀️'
|
||||||
|
elseif weather.data[n].icon == 'clear-night' then
|
||||||
|
return '🌙'
|
||||||
|
elseif weather.data[n].icon == 'rain' then
|
||||||
|
return '☔️'
|
||||||
|
elseif weather.data[n].icon == 'snow' then
|
||||||
|
return '❄️'
|
||||||
|
elseif weather.data[n].icon == 'sleet' then
|
||||||
|
return '🌨'
|
||||||
|
elseif weather.data[n].icon == 'wind' then
|
||||||
|
return '💨'
|
||||||
|
elseif weather.data[n].icon == 'fog' then
|
||||||
|
return '🌫'
|
||||||
|
elseif weather.data[n].icon == 'cloudy' then
|
||||||
|
return '☁️☁️'
|
||||||
|
elseif weather.data[n].icon == 'partly-cloudy-day' then
|
||||||
|
return '🌤'
|
||||||
|
elseif weather.data[n].icon == 'partly-cloudy-night' then
|
||||||
|
return '🌙☁️'
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_temp(weather, n, hourly)
|
||||||
|
if hourly then
|
||||||
|
local temperature = string.gsub(round(weather.data[n].temperature, 1), "%.", ",")
|
||||||
|
local condition = weather.data[n].summary
|
||||||
|
return temperature..'°C | '..get_condition_symbol(weather, n)..' '..condition
|
||||||
|
else
|
||||||
|
local day = string.gsub(round(weather.data[n].temperatureMax, 1), "%.", ",")
|
||||||
|
local night = string.gsub(round(weather.data[n].temperatureMin, 1), "%.", ",")
|
||||||
|
local condition = weather.data[n].summary
|
||||||
|
return '☀️ '..day..'°C | 🌙 '..night..'°C | '..get_condition_symbol(weather, n)..' '..condition
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function forecast:get_forecast(lat, lng)
|
||||||
|
print('Finde Wetter in '..lat..', '..lng)
|
||||||
|
local text = redis:get('telegram:cache:forecast:'..lat..','..lng)
|
||||||
|
if text then print('...aus dem Cache..') return text end
|
||||||
|
|
||||||
|
local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=currently,minutely,hourly,alerts,flags'
|
||||||
|
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = url,
|
||||||
|
method = "GET",
|
||||||
|
sink = ltn12.sink.table(response_body)
|
||||||
|
}
|
||||||
|
local ok, response_code, response_headers, response_status_line = HTTPS.request(request_constructor)
|
||||||
|
if not ok then return nil end
|
||||||
|
local data = JSON.decode(table.concat(response_body))
|
||||||
|
local ttl = string.sub(response_headers["cache-control"], 9)
|
||||||
|
|
||||||
|
|
||||||
|
local weather = data.daily
|
||||||
|
local city = get_city_name(lat, lng)
|
||||||
|
|
||||||
|
local header = '*Vorhersage für '..city..':*\n_'..weather.summary..'_\n'
|
||||||
|
|
||||||
|
local text = '*Heute:* '..get_temp(weather, 1)
|
||||||
|
local text = text..'\n*Morgen:* '..get_temp(weather, 2)
|
||||||
|
|
||||||
|
for day in pairs(weather.data) do
|
||||||
|
if day > 2 then
|
||||||
|
text = text..'\n*'..convert_timestamp(weather.data[day].time, '%a, %d.%m')..'*: '..get_temp(weather, day)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = string.gsub(text, "Mon", "Mo")
|
||||||
|
local text = string.gsub(text, "Tue", "Di")
|
||||||
|
local text = string.gsub(text, "Wed", "Mi")
|
||||||
|
local text = string.gsub(text, "Thu", "Do")
|
||||||
|
local text = string.gsub(text, "Fri", "Fr")
|
||||||
|
local text = string.gsub(text, "Sat", "Sa")
|
||||||
|
local text = string.gsub(text, "Sun", "So")
|
||||||
|
|
||||||
|
cache_data('forecast', lat..','..lng, header..text, tonumber(ttl), 'key')
|
||||||
|
|
||||||
|
return header..text
|
||||||
|
end
|
||||||
|
|
||||||
|
function forecast:get_forecast_hourly(lat, lng)
|
||||||
|
print('Finde stündliches Wetter in '..lat..', '..lng)
|
||||||
|
local text = redis:get('telegram:cache:forecast:'..lat..','..lng..':hourly')
|
||||||
|
if text then print('...aus dem Cache..') return text end
|
||||||
|
|
||||||
|
local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=currently,minutely,daily,alerts,flags'
|
||||||
|
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = url,
|
||||||
|
method = "GET",
|
||||||
|
sink = ltn12.sink.table(response_body)
|
||||||
|
}
|
||||||
|
local ok, response_code, response_headers, response_status_line = HTTPS.request(request_constructor)
|
||||||
|
if not ok then return nil end
|
||||||
|
local data = JSON.decode(table.concat(response_body))
|
||||||
|
local ttl = string.sub(response_headers["cache-control"], 9)
|
||||||
|
|
||||||
|
|
||||||
|
local weather = data.hourly
|
||||||
|
local city = get_city_name(lat, lng)
|
||||||
|
|
||||||
|
local header = '*24-Stunden-Vorhersage für '..city..':*\n_'..weather.summary..'_'
|
||||||
|
local text = ""
|
||||||
|
|
||||||
|
for hour in pairs(weather.data) do
|
||||||
|
if hour < 26 then
|
||||||
|
text = text..'\n*'..convert_timestamp(weather.data[hour].time, '%H:%M Uhr')..'* | '..get_temp(weather, hour, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cache_data('forecast', lat..','..lng..':hourly', header..text, tonumber(ttl), 'key')
|
||||||
|
|
||||||
|
return header..text
|
||||||
|
end
|
||||||
|
|
||||||
|
function forecast:action(msg, config, matches)
|
||||||
|
local user_id = msg.from.id
|
||||||
|
local city = get_location(user_id)
|
||||||
|
|
||||||
|
if matches[2] then
|
||||||
|
city = matches[2]
|
||||||
|
else
|
||||||
|
local set_location = get_location(user_id)
|
||||||
|
if not set_location then
|
||||||
|
city = 'Berlin, Deutschland'
|
||||||
|
else
|
||||||
|
city = set_location
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local lat = redis:hget('telegram:cache:weather:'..string.lower(city), 'lat')
|
||||||
|
local lng = redis:hget('telegram:cache:weather:'..string.lower(city), 'lng')
|
||||||
|
if not lat and not lng then
|
||||||
|
print('Koordinaten nicht eingespeichert, frage Google...')
|
||||||
|
coords = utilities.get_coords(city, config)
|
||||||
|
lat = coords.lat
|
||||||
|
lng = coords.lon
|
||||||
|
end
|
||||||
|
|
||||||
|
if not lat and not lng then
|
||||||
|
utilities.send_reply(self, msg, '*Diesen Ort gibt es nicht!*', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat)
|
||||||
|
redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng)
|
||||||
|
|
||||||
|
if matches[1] == '/forecasth' or matches[1] == '/fh' then
|
||||||
|
text = forecast:get_forecast_hourly(lat, lng)
|
||||||
|
else
|
||||||
|
text = forecast:get_forecast(lat, lng)
|
||||||
|
end
|
||||||
|
if not text then
|
||||||
|
text = '*Konnte die Wettervorhersage für diese Stadt nicht bekommen.*'
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, text, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return forecast
|
@ -21,11 +21,10 @@ function gImages:init(config)
|
|||||||
end
|
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):t('insfw', true).table
|
||||||
gImages.doc = [[```
|
gImages.doc = [[*
|
||||||
]]..config.cmd_pat..[[img <Suchbegriff>
|
]]..config.cmd_pat..[[img* _<Suchbegriff>_
|
||||||
Sucht Bild mit Google und versendet es (SafeSearch aktiv)
|
Sucht Bild mit Google und versendet es (SafeSearch aktiv)
|
||||||
Alias: ]]..config.cmd_pat..[[i
|
Alias: *]]..config.cmd_pat..[[i*]]
|
||||||
```]]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
gImages.command = 'img <Suchbegriff>'
|
gImages.command = 'img <Suchbegriff>'
|
||||||
@ -47,6 +46,7 @@ function gImages:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||||
local apikey = cred_data.google_apikey
|
local apikey = cred_data.google_apikey
|
||||||
local cseid = cred_data.google_cse_id
|
local cseid = cred_data.google_cse_id
|
||||||
local BASE_URL = 'https://www.googleapis.com/customsearch/v1'
|
local BASE_URL = 'https://www.googleapis.com/customsearch/v1'
|
||||||
@ -68,9 +68,7 @@ function gImages:action(msg, config)
|
|||||||
local img_url = jdat.items[i].link
|
local img_url = jdat.items[i].link
|
||||||
|
|
||||||
local file = download_to_file(img_url)
|
local file = download_to_file(img_url)
|
||||||
bindings.sendPhoto(self, {chat_id = msg.chat.id, caption = img_url}, {photo = file} )
|
utilities.send_photo(self, msg.chat.id, file, img_url)
|
||||||
os.remove(file)
|
|
||||||
print("Deleted: "..file)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return gImages
|
return gImages
|
||||||
|
77
otouto/plugins/github.lua
Normal file
77
otouto/plugins/github.lua
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
local github = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function github:init(config)
|
||||||
|
github.triggers = {
|
||||||
|
"github.com/([A-Za-z0-9-_-.-._.]+)/([A-Za-z0-9-_-.-._.]+)/commit/([a-z0-9-]+)",
|
||||||
|
"github.com/([A-Za-z0-9-_-.-._.]+)/([A-Za-z0-9-_-.-._.]+)/?$"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local BASE_URL = 'https://api.github.com'
|
||||||
|
|
||||||
|
function github:get_gh_data(gh_code, gh_commit_sha)
|
||||||
|
if gh_commit_sha == nil then
|
||||||
|
url = BASE_URL..'/repos/'..gh_code
|
||||||
|
else
|
||||||
|
url = BASE_URL..'/repos/'..gh_code..'/git/commits/'..gh_commit_sha
|
||||||
|
end
|
||||||
|
local res,code = https.request(url)
|
||||||
|
if code ~= 200 then return "HTTP-FEHLER" end
|
||||||
|
local data = json.decode(res)
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function github:send_github_data(data)
|
||||||
|
if not data.owner then return nil end
|
||||||
|
local name = '*'..data.name..'*'
|
||||||
|
local description = '_'..data.description..'_'
|
||||||
|
local owner = data.owner.login
|
||||||
|
local clone_url = data.clone_url
|
||||||
|
if data.language == nil or data.language == "" then
|
||||||
|
language = ''
|
||||||
|
else
|
||||||
|
language = '\nSprache: '..data.language
|
||||||
|
end
|
||||||
|
if data.open_issues_count == 0 then
|
||||||
|
issues = ''
|
||||||
|
else
|
||||||
|
issues = '\nOffene Bugreports: '..data.open_issues_count
|
||||||
|
end
|
||||||
|
if data.homepage == nil or data.homepage == "" then
|
||||||
|
homepage = ''
|
||||||
|
else
|
||||||
|
homepage = '\n[Homepage besuchen]('..data.homepage..')'
|
||||||
|
end
|
||||||
|
local text = name..' von '..owner..'\n'..description..'\n`git clone '..clone_url..'`'..language..issues..homepage
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function github:send_gh_commit_data(gh_code, gh_commit_sha, data)
|
||||||
|
if not data.committer then return nil end
|
||||||
|
local committer = data.committer.name
|
||||||
|
local message = data.message
|
||||||
|
local text = '`'..gh_code..'@'..gh_commit_sha..'` von *'..committer..'*:\n'..message
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function github:action(msg, config, matches)
|
||||||
|
local gh_code = matches[1]..'/'..matches[2]
|
||||||
|
local gh_commit_sha = matches[3]
|
||||||
|
local data = github:get_gh_data(gh_code, gh_commit_sha)
|
||||||
|
if not gh_commit_sha then
|
||||||
|
output = github:send_github_data(data)
|
||||||
|
else
|
||||||
|
output = github:send_gh_commit_data(gh_code, gh_commit_sha, data)
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, output, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return github
|
16
otouto/plugins/images.lua
Normal file
16
otouto/plugins/images.lua
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
local images = {}
|
||||||
|
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
images.triggers = {
|
||||||
|
"(https?://[%w-_%%%.%?%.:,/%+=~&%[%]]+%.[Pp][Nn][Gg])$",
|
||||||
|
"(https?://[%w-_%%%.%?%.:,/%+=~&%[%]]+%.[Jj][Pp][Ee]?[Gg])$"
|
||||||
|
}
|
||||||
|
|
||||||
|
function images:action(msg)
|
||||||
|
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||||
|
local url = matches[1]
|
||||||
|
local file = download_to_file(url)
|
||||||
|
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
return images
|
@ -51,7 +51,7 @@ function imdb:action(msg, config)
|
|||||||
|
|
||||||
if jdat.Poster ~= "N/A" then
|
if jdat.Poster ~= "N/A" then
|
||||||
local file = download_to_file(jdat.Poster)
|
local file = download_to_file(jdat.Poster)
|
||||||
bindings.sendPhoto(self, {chat_id = msg.chat.id}, {photo = file} )
|
utilities.send_photo(self, msg.chat.id, file)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
69
otouto/plugins/location_manager.lua
Normal file
69
otouto/plugins/location_manager.lua
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
local loc_manager = {}
|
||||||
|
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function loc_manager:init(config)
|
||||||
|
loc_manager.triggers = {
|
||||||
|
"^/location (set) (.*)$",
|
||||||
|
"^/location (del)$",
|
||||||
|
"^/location$"
|
||||||
|
}
|
||||||
|
loc_manager.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[location*: Gibt deinen gesetzten Wohnort aus
|
||||||
|
*]]..config.cmd_pat..[[location* _set_ _<Ort>_: Setzt deinen Wohnort auf diesen Ort
|
||||||
|
*]]..config.cmd_pat..[[location* _del_: Löscht deinen angegebenen Wohnort
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
loc_manager.command = 'location'
|
||||||
|
|
||||||
|
function loc_manager:set_location(user_id, location)
|
||||||
|
local hash = 'user:'..user_id
|
||||||
|
local set_location = get_location(user_id)
|
||||||
|
if set_location == location then
|
||||||
|
return 'Dieser Ort wurde bereits gesetzt.'
|
||||||
|
else
|
||||||
|
print('Setting location in redis hash '..hash..' to location')
|
||||||
|
redis:hset(hash, 'location', location)
|
||||||
|
return 'Dein Wohnort wurde auf *'..location..'* festgelegt.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function loc_manager:del_location(user_id)
|
||||||
|
local hash = 'user:'..user_id
|
||||||
|
local set_location = get_location(user_id)
|
||||||
|
if not set_location then
|
||||||
|
return 'Du hast keinen Ort gesetzt'
|
||||||
|
else
|
||||||
|
print('Setting location in redis hash '..hash..' to false')
|
||||||
|
-- We set the location to false, because deleting the value blocks redis for a few milliseconds
|
||||||
|
redis:hset(hash, 'location', false)
|
||||||
|
return 'Dein Wohnort *'..set_location..'* wurde gelöscht!'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function loc_manager:action(msg, config, matches)
|
||||||
|
local user_id = msg.from.id
|
||||||
|
|
||||||
|
if matches[1] == 'set' then
|
||||||
|
utilities.send_reply(self, msg, loc_manager:set_location(user_id, matches[2]), true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == 'del' then
|
||||||
|
utilities.send_reply(self, msg, loc_manager:del_location(user_id), true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
local set_location = get_location(user_id)
|
||||||
|
if not set_location then
|
||||||
|
utilities.send_reply(self, msg, '*Du hast keinen Ort gesetzt!*', true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
local coords = utilities.get_coords(set_location, config)
|
||||||
|
utilities.send_location(self, msg.chat.id, coords.lat, coords.lon, msg.message_id)
|
||||||
|
utilities.send_reply(self, msg, 'Gesetzter Wohnort: *'..set_location..'*', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return loc_manager
|
67
otouto/plugins/media.lua
Normal file
67
otouto/plugins/media.lua
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
local media = {}
|
||||||
|
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local mimetype = (loadfile "./otouto/mimetype.lua")()
|
||||||
|
|
||||||
|
media.triggers = {
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(gif))$",
|
||||||
|
"^(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(mp4))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(pdf))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(ogg))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(zip))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(tar.gz))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(7z))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(mp3))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(rar))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(wmv))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(doc))$",
|
||||||
|
"^(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(avi))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(wav))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(apk))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(webm))$",
|
||||||
|
"^(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(ogv))$",
|
||||||
|
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(webp))$"
|
||||||
|
}
|
||||||
|
|
||||||
|
function media:action(msg)
|
||||||
|
local url = matches[1]
|
||||||
|
local ext = matches[2]
|
||||||
|
local receiver = msg.chat.id
|
||||||
|
|
||||||
|
utilities.send_typing(self, receiver, 'upload_document')
|
||||||
|
local file = download_to_file(url)
|
||||||
|
local mime_type = mimetype.get_content_type_no_sub(ext)
|
||||||
|
|
||||||
|
if ext == 'gif' then
|
||||||
|
print('send gif')
|
||||||
|
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif mime_type == 'text' then
|
||||||
|
print('send_document')
|
||||||
|
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif mime_type == 'image' then
|
||||||
|
print('send_photo')
|
||||||
|
utilities.send_photo(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif mime_type == 'audio' then
|
||||||
|
print('send_audio')
|
||||||
|
utilities.send_audio(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif mime_type == 'video' then
|
||||||
|
print('send_video')
|
||||||
|
utilities.send_video(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
else
|
||||||
|
print('send_file')
|
||||||
|
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return media
|
45
otouto/plugins/pasteee.lua
Normal file
45
otouto/plugins/pasteee.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
local pasteee = {}
|
||||||
|
|
||||||
|
local bot = require('otouto.bot')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
|
function pasteee:init(config)
|
||||||
|
if not cred_data.pasteee_key then
|
||||||
|
print('Missing config value: pasteee_key.')
|
||||||
|
print('pasteee.lua will not be enabled, listquotes won\'t be available.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
pasteee.triggers = {
|
||||||
|
"^/pasteee (.*)$"
|
||||||
|
}
|
||||||
|
pasteee.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[pasteee* _<Text>_: Postet Text auf Paste.ee]]
|
||||||
|
end
|
||||||
|
|
||||||
|
pasteee.command = 'pasteee <Text>'
|
||||||
|
|
||||||
|
local key = cred_data.pasteee_key
|
||||||
|
|
||||||
|
function upload(text, noraw)
|
||||||
|
local url = "https://paste.ee/api"
|
||||||
|
local pet = post_petition(url, 'key='..key..'&paste='..text..'&format=json')
|
||||||
|
if pet.status ~= 'success' then return 'Ein Fehler ist aufgetreten: '..pet.error, true end
|
||||||
|
if noraw then
|
||||||
|
return pet.paste.link
|
||||||
|
else
|
||||||
|
return pet.paste.raw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pasteee:action(msg, config, matches)
|
||||||
|
local text = matches[1]
|
||||||
|
local link, iserror = upload(text)
|
||||||
|
if iserror then
|
||||||
|
utilities.send_reply(self, msg, link)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, '[Text auf Paste.ee ansehen]('..link..')', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return pasteee
|
@ -7,7 +7,7 @@ patterns.triggers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function patterns:action(msg)
|
function patterns:action(msg)
|
||||||
if not msg.reply_to_message then return end
|
if not msg.reply_to_message then return true end
|
||||||
local output = msg.reply_to_message.text
|
local output = msg.reply_to_message.text
|
||||||
if msg.reply_to_message.from.id == self.info.id then
|
if msg.reply_to_message.from.id == self.info.id then
|
||||||
output = output:gsub('Did you mean:\n"', '')
|
output = output:gsub('Did you mean:\n"', '')
|
||||||
@ -22,8 +22,7 @@ function patterns:action(msg)
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
if res == false then
|
if res == false then
|
||||||
output = 'Malformed pattern!'
|
utilities.send_reply(self, msg, 'Malformed pattern!')
|
||||||
utilities.send_reply(self, msg, output)
|
|
||||||
else
|
else
|
||||||
output = output:sub(1, 4000)
|
output = output:sub(1, 4000)
|
||||||
output = 'Did you mean:\n"' .. output .. '"'
|
output = 'Did you mean:\n"' .. output .. '"'
|
||||||
|
111
otouto/plugins/quotes.lua
Normal file
111
otouto/plugins/quotes.lua
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
local quotes = {}
|
||||||
|
|
||||||
|
local bot = require('otouto.bot')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
require("./otouto/plugins/pasteee")
|
||||||
|
|
||||||
|
function quotes:init(config)
|
||||||
|
quotes.triggers = {
|
||||||
|
"^/(delquote) (.+)$",
|
||||||
|
"^/(addquote) (.+)$",
|
||||||
|
"^/(quote)$",
|
||||||
|
"^/(listquotes)$"
|
||||||
|
}
|
||||||
|
quotes.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[addquote* _<Zitat>_: Fügt Zitat hinzu.
|
||||||
|
*]]..config.cmd_pat..[[delquote* _<Zitat>_: Löscht das Zitat (nur Superuser)
|
||||||
|
*]]..config.cmd_pat..[[quote*: Gibt zufälliges Zitat aus
|
||||||
|
*]]..config.cmd_pat..[[listquotes*: Listet alle Zitate auf
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
quotes.command = 'quote'
|
||||||
|
|
||||||
|
function quotes:save_quote(msg)
|
||||||
|
if msg.text:sub(11):isempty() then
|
||||||
|
return "Benutzung: /addquote [Zitat]"
|
||||||
|
end
|
||||||
|
|
||||||
|
local quote = msg.text:sub(11)
|
||||||
|
local hash = get_redis_hash(msg, 'quotes')
|
||||||
|
print('Saving quote to redis set '..hash)
|
||||||
|
redis:sadd(hash, quote)
|
||||||
|
return '*Gespeichert!*'
|
||||||
|
end
|
||||||
|
|
||||||
|
function quotes:delete_quote(msg)
|
||||||
|
if msg.text:sub(11):isempty() then
|
||||||
|
return "Benutzung: /delquote [Zitat]"
|
||||||
|
end
|
||||||
|
|
||||||
|
local quote = msg.text:sub(11)
|
||||||
|
local hash = get_redis_hash(msg, 'quotes')
|
||||||
|
print('Deleting quote from redis set '..hash)
|
||||||
|
if redis:sismember(hash, quote) == true then
|
||||||
|
redis:srem(hash, quote)
|
||||||
|
return '*Zitat erfolgreich gelöscht!*'
|
||||||
|
else
|
||||||
|
return 'Dieses Zitat existiert nicht.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function quotes:get_quote(msg)
|
||||||
|
local hash = get_redis_hash(msg, 'quotes')
|
||||||
|
|
||||||
|
if hash then
|
||||||
|
print('Getting quote from redis set '..hash)
|
||||||
|
local quotes_table = redis:smembers(hash)
|
||||||
|
if not quotes_table[1] then
|
||||||
|
return 'Es wurden noch keine Zitate gespeichert.\nSpeichere doch welche mit /addquote [Zitat]'
|
||||||
|
else
|
||||||
|
return quotes_table[math.random(1,#quotes_table)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function quotes:list_quotes(msg)
|
||||||
|
local hash = get_redis_hash(msg, 'quotes')
|
||||||
|
|
||||||
|
if hash then
|
||||||
|
print('Getting quotes from redis set '..hash)
|
||||||
|
local quotes_table = redis:smembers(hash)
|
||||||
|
local text = ""
|
||||||
|
for num,quote in pairs(quotes_table) do
|
||||||
|
text = text..num..") "..quote..'\n'
|
||||||
|
end
|
||||||
|
if not text or text == "" then
|
||||||
|
return 'Es wurden noch keine Zitate gespeichert.\nSpeichere doch welche mit !addquote [Zitat]'
|
||||||
|
else
|
||||||
|
return upload(text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function quotes:action(msg, config, matches)
|
||||||
|
if matches[1] == "quote" then
|
||||||
|
utilities.send_message(self, msg.chat.id, quotes:get_quote(msg), true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == "addquote" and matches[2] then
|
||||||
|
utilities.send_reply(self, msg, quotes:save_quote(msg), true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == "delquote" and matches[2] then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, quotes:delete_quote(msg), true)
|
||||||
|
return
|
||||||
|
elseif matches[1] == "listquotes" then
|
||||||
|
local link, iserror = quotes:list_quotes(msg)
|
||||||
|
if iserror then
|
||||||
|
utilities.send_reply(self, msg, link)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, '[Lise aller Zitate auf Paste.ee ansehen]('..link..')', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, quotes.doc, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return quotes
|
86
otouto/plugins/respond.lua
Normal file
86
otouto/plugins/respond.lua
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
local respond = {}
|
||||||
|
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
|
||||||
|
function respond:init(config)
|
||||||
|
respond.triggers = {
|
||||||
|
"([Ff][Gg][Tt].? [Ss][Ww][Ii][Ff][Tt])",
|
||||||
|
"([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee][Ss])",
|
||||||
|
"([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee][Rr])",
|
||||||
|
"([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee])",
|
||||||
|
"^[Bb][Oo][Tt]%??$",
|
||||||
|
"^/([Ll][Oo][Dd])$",
|
||||||
|
"^/([Ll][Ff])$",
|
||||||
|
"^/([Kk][Aa])$",
|
||||||
|
"^/([Ii][Dd][Kk])$",
|
||||||
|
"^/([Nn][Bb][Cc])$",
|
||||||
|
"^/([Ii][Dd][Cc])$",
|
||||||
|
"^%*([Ff][Rr][Oo][Ss][Cc][Hh])%*",
|
||||||
|
"^/([Ff][Rr][Oo][Ss][Cc][Hh])$",
|
||||||
|
"^%(([Ii][Nn][Ll][Oo][Vv][Ee])%)$",
|
||||||
|
"^/[Ww][Aa][Tt]$"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
respond.command = 'lod, /lf, /nbc, /wat'
|
||||||
|
|
||||||
|
function respond:action(msg, config, matches)
|
||||||
|
local user_name = get_name(msg)
|
||||||
|
local receiver = msg.chat.id
|
||||||
|
local GDRIVE_URL = 'https://de2319bd4b4b51a5ef2939a7638c1d35646f49f8.googledrive.com/host/0B_mfIlDgPiyqU25vUHZqZE9IUXc'
|
||||||
|
if user_name == "DefenderX" then user_name = "Deffu" end
|
||||||
|
|
||||||
|
if string.match(msg.text, "[Ff][Gg][Tt].? [Ss][Ww][Ii][Ff][Tt]") then
|
||||||
|
utilities.send_message(self, receiver, 'Dünnes Eis, '..user_name..'!')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee][Ss])") then
|
||||||
|
utilities.send_message(self, receiver, '*einziges')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee][Rr])") then
|
||||||
|
utilities.send_message(self, receiver, '*einziger')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "([Ee][Ii][Nn][Zz][Ii][Gg][Ss][Tt][Ee])") then
|
||||||
|
utilities.send_message(self, receiver, '*einzige')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Bb][Oo][Tt]%??") then
|
||||||
|
utilities.send_reply(self, msg, '*Ich bin da, '..user_name..'!*', true)
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Ll][Oo][Dd]") then
|
||||||
|
utilities.send_message(self, receiver, 'ಠ_ಠ')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Ll][Ff]") then
|
||||||
|
utilities.send_message(self, receiver, '( ͡° ͜ʖ ͡°)')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Nn][Bb][Cc]") or string.match(msg.text, "[Ii][Dd][Cc]") or string.match(msg.text, "[Kk][Aa]") or string.match(msg.text, "[Ii][Dd][Kk]") then
|
||||||
|
utilities.send_message(self, receiver, [[¯\_(ツ)_/¯]])
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Ff][Rr][Oo][Ss][Cc][Hh]") then
|
||||||
|
utilities.send_message(self, receiver, '🐸🐸🐸')
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Ii][Nn][Ll][Oo][Vv][Ee]") then
|
||||||
|
local file = download_to_file(GDRIVE_URL..'/inlove.gif')
|
||||||
|
utilities.send_document(self, receiver, file)
|
||||||
|
return
|
||||||
|
elseif string.match(msg.text, "[Ww][Aa][Tt]") then
|
||||||
|
local WAT_URL = GDRIVE_URL..'/wat'
|
||||||
|
local wats = {
|
||||||
|
"/wat1.jpg",
|
||||||
|
"/wat2.jpg",
|
||||||
|
"/wat3.jpg",
|
||||||
|
"/wat4.jpg",
|
||||||
|
"/wat5.jpg",
|
||||||
|
"/wat6.jpg",
|
||||||
|
"/wat7.jpg",
|
||||||
|
"/wat8.jpg"
|
||||||
|
}
|
||||||
|
local random_wat = math.random(5)
|
||||||
|
local file = download_to_file(WAT_URL..wats[random_wat])
|
||||||
|
utilities.send_photo(self, receiver, file)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return respond
|
31
otouto/plugins/roll.lua
Normal file
31
otouto/plugins/roll.lua
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
local roll = {}
|
||||||
|
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
|
roll.command = 'roll'
|
||||||
|
|
||||||
|
function roll:init(config)
|
||||||
|
roll.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
||||||
|
roll.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[roll*: Werfe einen Würfel]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local canroll = {
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6"
|
||||||
|
}
|
||||||
|
|
||||||
|
function roll:roll_dice()
|
||||||
|
local randomroll = math.random(6)
|
||||||
|
return canroll[randomroll]
|
||||||
|
end
|
||||||
|
|
||||||
|
function roll:action(msg)
|
||||||
|
utilities.send_reply(self, msg, 'Du hast eine *'..roll:roll_dice()..'* gewürfelt.', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return roll
|
112
otouto/plugins/tagesschau_eil.lua
Normal file
112
otouto/plugins/tagesschau_eil.lua
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
local tagesschau_eil = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local url = require('socket.url')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
tagesschau_eil.command = 'eil <sub/del>'
|
||||||
|
|
||||||
|
function tagesschau_eil:init(config)
|
||||||
|
tagesschau_eil.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('eil', true).table
|
||||||
|
tagesschau_eil.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[eil* _sub_: Eilmeldungen abonnieren
|
||||||
|
*]]..config.cmd_pat..[[eil* _del_: Eilmeldungen deabonnieren
|
||||||
|
*]]..config.cmd_pat..[[eil* _sync_: Nach neuen Eilmeldungen prüfen (nur Superuser)]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local makeOurDate = function(dateString)
|
||||||
|
local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+)%:(%d+)%:(%d+)"
|
||||||
|
local year, month, day, hours, minutes, seconds = dateString:match(pattern)
|
||||||
|
return day..'.'..month..'.'..year..' um '..hours..':'..minutes..':'..seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
local url = 'http://www.tagesschau.de/api'
|
||||||
|
local hash = 'telegram:tagesschau'
|
||||||
|
|
||||||
|
function tagesschau_eil:abonnieren(id)
|
||||||
|
if redis:sismember(hash..':subs', id) == false then
|
||||||
|
redis:sadd(hash..':subs', id)
|
||||||
|
return '*Eilmeldungen abonniert.*'
|
||||||
|
else
|
||||||
|
return 'Die Eilmeldungen wurden hier bereits abonniert.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tagesschau_eil:deabonnieren(id)
|
||||||
|
if redis:sismember(hash..':subs', id) == true then
|
||||||
|
redis:srem(hash..':subs', id)
|
||||||
|
return '*Eilmeldungen deabonniert.*'
|
||||||
|
else
|
||||||
|
return 'Die Eilmeldungen wurden hier noch nicht abonniert.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tagesschau_eil: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, tagesschau_eil.doc, true, msg.message_id, true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local id = "user#id" .. msg.from.id
|
||||||
|
if msg.chat.type == 'channel' then
|
||||||
|
print('Kanäle werden momentan nicht unterstützt')
|
||||||
|
end
|
||||||
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
|
id = 'chat#id'..msg.chat.id
|
||||||
|
end
|
||||||
|
|
||||||
|
if input:match('(sub)$') then
|
||||||
|
local output = tagesschau_eil:abonnieren(id)
|
||||||
|
utilities.send_reply(self, msg, output, true)
|
||||||
|
elseif input:match('(del)$') then
|
||||||
|
local output = tagesschau_eil:deabonnieren(id)
|
||||||
|
utilities.send_reply(self, msg, output, true)
|
||||||
|
elseif input:match('(sync)$') then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
tagesschau_eil:cron(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
function tagesschau_eil:cron(self_plz)
|
||||||
|
if not self.BASE_URL then
|
||||||
|
self = self_plz
|
||||||
|
end
|
||||||
|
-- print('EIL: Prüfe...')
|
||||||
|
local last_eil = redis:get(hash..':last_entry')
|
||||||
|
local res,code = http.request(url)
|
||||||
|
local data = json.decode(res)
|
||||||
|
if code ~= 200 then return end
|
||||||
|
if not data then return end
|
||||||
|
if data.breakingnews[1] then
|
||||||
|
if data.breakingnews[1].details ~= last_eil then
|
||||||
|
local title = '#EIL: *'..data.breakingnews[1].headline..'*'
|
||||||
|
local news = data.breakingnews[1].shorttext
|
||||||
|
local posted_at = makeOurDate(data.breakingnews[1].date)..' Uhr'
|
||||||
|
local post_url = string.gsub(data.breakingnews[1].details, '/api/', '/')
|
||||||
|
local post_url = string.gsub(post_url, '.json', '.html')
|
||||||
|
local eil = title..'\n_'..posted_at..'_\n'..news..'\n[Artikel aufrufen]('..post_url..')'
|
||||||
|
redis:set(hash..':last_entry', data.breakingnews[1].details)
|
||||||
|
for _,user in pairs(redis:smembers(hash..':subs')) do
|
||||||
|
local user = string.gsub(user, 'chat%#id', '')
|
||||||
|
local user = string.gsub(user, 'user%#id', '')
|
||||||
|
utilities.send_message(self, user, eil, true, nil, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tagesschau_eil
|
@ -140,15 +140,11 @@ function twitter:action(msg)
|
|||||||
utilities.send_reply(self, msg, header .. "\n" .. text.."\n"..footer)
|
utilities.send_reply(self, msg, header .. "\n" .. text.."\n"..footer)
|
||||||
for k, v in pairs(images) do
|
for k, v in pairs(images) do
|
||||||
local file = download_to_file(v)
|
local file = download_to_file(v)
|
||||||
bindings.sendPhoto(self, {chat_id = msg.chat.id}, {photo = file} )
|
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
os.remove(file)
|
|
||||||
print("Deleted: "..file)
|
|
||||||
end
|
end
|
||||||
for k, v in pairs(videos) do
|
for k, v in pairs(videos) do
|
||||||
local file = download_to_file(v)
|
local file = download_to_file(v)
|
||||||
bindings.sendVideo(self, {chat_id = msg.chat.id}, {video = file} )
|
utilities.send_video(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
os.remove(file)
|
|
||||||
print("Deleted: "..file)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
349
otouto/plugins/twitter_send.lua
Normal file
349
otouto/plugins/twitter_send.lua
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
local twitter_send = {}
|
||||||
|
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
|
local json = require('dkjson')
|
||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local OAuth = require "OAuth"
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
|
function twitter_send:init(config)
|
||||||
|
if not cred_data.tw_consumer_key then
|
||||||
|
print('Missing config value: tw_consumer_key.')
|
||||||
|
print('twitter_send.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
elseif not cred_data.tw_consumer_secret then
|
||||||
|
print('Missing config value: tw_consumer_secret.')
|
||||||
|
print('twitter_send.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
twitter_send.triggers = {
|
||||||
|
"^/tw (auth) (%d+)",
|
||||||
|
"^/tw (unauth)$",
|
||||||
|
"^/tw (verify)$",
|
||||||
|
"^/tw (.+)",
|
||||||
|
"^/(twwhitelist add) (%d+)",
|
||||||
|
"^/(twwhitelist del) (%d+)"
|
||||||
|
}
|
||||||
|
twitter_send.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[tw* _<Text>_: Sendet einen Tweet an den Account, der im Chat angemeldet ist
|
||||||
|
*]]..config.cmd_pat..[[tw* _verify_: Gibt den angemeldeten User aus, inklusive Profilbild
|
||||||
|
*]]..config.cmd_pat..[[twwitelist* _add_ _<user>_: Schaltet User für die Tweet-Funktion frei
|
||||||
|
*]]..config.cmd_pat..[[twwitelist* _del_ _<user>_: Entfernt User von der Tweet-Whitelist
|
||||||
|
*]]..config.cmd_pat..[[tw* _auth_ _<PIN>_: Meldet mit dieser PIN an (Setup)
|
||||||
|
*]]..config.cmd_pat..[[tw* _unauth_: Meldet Twitter-Account ab
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
twitter_send.command = 'tw <Tweet>'
|
||||||
|
|
||||||
|
local consumer_key = cred_data.tw_consumer_key
|
||||||
|
local consumer_secret = cred_data.tw_consumer_secret
|
||||||
|
|
||||||
|
function can_send_tweet(msg)
|
||||||
|
local hash = 'user:'..msg.from.id
|
||||||
|
local var = redis:hget(hash, 'can_send_tweet')
|
||||||
|
if var == "true" then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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"
|
||||||
|
})
|
||||||
|
|
||||||
|
function twitter_send:do_twitter_authorization_flow(hash, is_chat)
|
||||||
|
local callback_url = "oob"
|
||||||
|
local values = client:RequestToken({ oauth_callback = callback_url })
|
||||||
|
local oauth_token = values.oauth_token
|
||||||
|
local oauth_token_secret = values.oauth_token_secret
|
||||||
|
|
||||||
|
-- save temporary oauth keys
|
||||||
|
redis:hset(hash, 'oauth_token', oauth_token)
|
||||||
|
redis:hset(hash, 'oauth_token_secret', oauth_token_secret)
|
||||||
|
|
||||||
|
local auth_url = client:BuildAuthorizationUrl({ oauth_callback = callback_url, force_login = true })
|
||||||
|
if is_chat then
|
||||||
|
return 'Bitte schließe den Vorgang ab, indem du unten auf den Link klickst und mir die angezeigte PIN per `/tw auth PIN` *im Chat von gerade* übergibst.\n[Bei Twitter anmelden]('..auth_url..')'
|
||||||
|
else
|
||||||
|
return 'Bitte schließe den Vorgang ab, indem du unten auf den Link klickst und mir die angezeigte PIN per `/tw auth PIN` übergibst.\n[Bei Twitter anmelden]('..auth_url..')'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:get_twitter_access_token(hash, oauth_verifier, oauth_token, oauth_token_secret)
|
||||||
|
local oauth_verifier = tostring(oauth_verifier) -- must be a string
|
||||||
|
|
||||||
|
-- now we'll use the tokens we got in the RequestToken call, plus our PIN
|
||||||
|
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 = oauth_token,
|
||||||
|
OAuthVerifier = oauth_verifier
|
||||||
|
})
|
||||||
|
client:SetTokenSecret(oauth_token_secret)
|
||||||
|
|
||||||
|
local values, err, headers, status, body = client:GetAccessToken()
|
||||||
|
if err then return 'Einloggen fehlgeschlagen!' end
|
||||||
|
|
||||||
|
-- save permanent oauth keys
|
||||||
|
redis:hset(hash, 'oauth_token', values.oauth_token)
|
||||||
|
redis:hset(hash, 'oauth_token_secret', values.oauth_token_secret)
|
||||||
|
|
||||||
|
return 'Erfolgreich eingeloggt als "@'..values.screen_name..'" (User-ID: '..values.user_id..')'
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:reset_twitter_auth(hash, frominvalid)
|
||||||
|
redis:hdel(hash, 'oauth_token')
|
||||||
|
redis:hdel(hash, 'oauth_token_secret')
|
||||||
|
if frominvalid then
|
||||||
|
return '*Authentifizierung nicht erfolgreich, wird zurückgesetzt...*'
|
||||||
|
else
|
||||||
|
return '*Erfolgreich abgemeldet!* Entziehe den Zugriff endgültig in deinen [Twitter-Einstellungen](https://twitter.com/settings/applications)!'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:resolve_url(url)
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = url,
|
||||||
|
method = "HEAD",
|
||||||
|
sink = ltn12.sink.table(response_body),
|
||||||
|
headers = {},
|
||||||
|
redirect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local ok, response_code, response_headers, response_status_line = http.request(request_constructor)
|
||||||
|
if ok and response_headers.location then
|
||||||
|
return response_headers.location
|
||||||
|
else
|
||||||
|
return url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:twitter_verify_credentials(oauth_token, oauth_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 = oauth_token,
|
||||||
|
OAuthTokenSecret = oauth_token_secret
|
||||||
|
})
|
||||||
|
|
||||||
|
local response_code, response_headers, response_status_line, response_body =
|
||||||
|
client:PerformRequest(
|
||||||
|
"GET", "https://api.twitter.com/1.1/account/verify_credentials.json", {
|
||||||
|
include_entities = false,
|
||||||
|
skip_status = true,
|
||||||
|
include_email = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
local response = json.decode(response_body)
|
||||||
|
if response_code == 401 then
|
||||||
|
return twitter_send:reset_twitter_auth(hash, true)
|
||||||
|
end
|
||||||
|
if response_code ~= 200 then
|
||||||
|
return 'HTTP-Fehler '..response_code..': '..data.errors[1].message
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: copied straight from the twitter_user plugin, maybe we can do it better?
|
||||||
|
local full_name = response.name
|
||||||
|
local user_name = response.screen_name
|
||||||
|
if response.verified then
|
||||||
|
user_name = user_name..' ✅'
|
||||||
|
end
|
||||||
|
if response.protected then
|
||||||
|
user_name = user_name..' 🔒'
|
||||||
|
end
|
||||||
|
local header = full_name.. " (@" ..user_name.. ")\n"
|
||||||
|
|
||||||
|
local description = unescape(response.description)
|
||||||
|
if response.location then
|
||||||
|
location = response.location
|
||||||
|
else
|
||||||
|
location = ''
|
||||||
|
end
|
||||||
|
if response.url and response.location ~= '' then
|
||||||
|
url = ' | '..twitter_send:resolve_url(response.url)..'\n'
|
||||||
|
elseif response.url and response.location == '' then
|
||||||
|
url = twitter_send:resolve_url(response.url)..'\n'
|
||||||
|
else
|
||||||
|
url = '\n'
|
||||||
|
end
|
||||||
|
|
||||||
|
local body = description..'\n'..location..url
|
||||||
|
|
||||||
|
local favorites = comma_value(response.favourites_count)
|
||||||
|
local follower = comma_value(response.followers_count)
|
||||||
|
local following = comma_value(response.friends_count)
|
||||||
|
local statuses = comma_value(response.statuses_count)
|
||||||
|
local footer = statuses..' Tweets, '..follower..' Follower, '..following..' folge ich, '..favorites..' Tweets favorisiert'
|
||||||
|
|
||||||
|
local text = 'Eingeloggter Account:\n'..header..body..footer
|
||||||
|
local pp_url = string.gsub(response.profile_image_url_https, "normal", "400x400")
|
||||||
|
|
||||||
|
return text, pp_url
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:send_tweet(tweet, oauth_token, oauth_token_secret, hash)
|
||||||
|
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 = oauth_token,
|
||||||
|
OAuthTokenSecret = oauth_token_secret
|
||||||
|
})
|
||||||
|
|
||||||
|
local response_code, response_headers, response_status_line, response_body =
|
||||||
|
client:PerformRequest(
|
||||||
|
"POST", "https://api.twitter.com/1.1/statuses/update.json", {
|
||||||
|
status = tweet
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
local data = json.decode(response_body)
|
||||||
|
if response_code == 401 then
|
||||||
|
return twitter_send:reset_twitter_auth(hash, true)
|
||||||
|
end
|
||||||
|
if response_code ~= 200 then
|
||||||
|
return 'HTTP-Fehler '..response_code..': '..data.errors[1].message
|
||||||
|
end
|
||||||
|
|
||||||
|
local statusnumber = comma_value(data.user.statuses_count)
|
||||||
|
local screen_name = data.user.screen_name
|
||||||
|
local status_id = data.id_str
|
||||||
|
|
||||||
|
return '*Tweet #'..statusnumber..' gesendet!* [Auf Twitter ansehen](https://twitter.com/statuses/'..status_id..')'
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:add_to_twitter_whitelist(user_id)
|
||||||
|
local hash = 'user:'..user_id
|
||||||
|
local whitelisted = redis:hget(hash, 'can_send_tweet')
|
||||||
|
if whitelisted ~= 'true' then
|
||||||
|
print('Setting can_send_tweet in redis hash '..hash..' to true')
|
||||||
|
redis:hset(hash, 'can_send_tweet', true)
|
||||||
|
return '*User '..user_id..' kann jetzt Tweets senden!*'
|
||||||
|
else
|
||||||
|
return '*User '..user_id..' kann schon Tweets senden.*'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:del_from_twitter_whitelist(user_id)
|
||||||
|
local hash = 'user:'..user_id
|
||||||
|
local whitelisted = redis:hget(hash, 'can_send_tweet')
|
||||||
|
if whitelisted == 'true' then
|
||||||
|
print('Setting can_send_tweet in redis hash '..hash..' to false')
|
||||||
|
redis:hset(hash, 'can_send_tweet', false)
|
||||||
|
return '*User '..user_id..' kann jetzt keine Tweets mehr senden!*'
|
||||||
|
else
|
||||||
|
return '*User '..user_id..' ist nicht whitelisted.*'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function twitter_send:action(msg, config, matches)
|
||||||
|
if matches[1] == "twwhitelist add" and matches[2] then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, twitter_send:add_to_twitter_whitelist(matches[2]), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == "twwhitelist del" and matches[2] then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, twitter_send:del_from_twitter_whitelist(matches[2]), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local hash = get_redis_hash(msg, 'twitter')
|
||||||
|
local oauth_token = redis:hget(hash, 'oauth_token')
|
||||||
|
local oauth_token_secret = redis:hget(hash, 'oauth_token_secret')
|
||||||
|
|
||||||
|
-- Thanks to the great doc at https://github.com/ignacio/LuaOAuth#a-more-involved-example
|
||||||
|
if not oauth_token and not oauth_token_secret then
|
||||||
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
-- maybe we can edit the older message to update it to "logged in!"?
|
||||||
|
-- this should be interesting: https://core.telegram.org/bots/api#editmessagetext
|
||||||
|
local text = twitter_send:do_twitter_authorization_flow(hash, true)
|
||||||
|
local res = utilities.send_message(self, msg.from.id, text, true, nil, true)
|
||||||
|
if not res then
|
||||||
|
utilities.send_reply(self, msg, 'Bitte starte mich zuerst [privat](http://telegram.me/' .. self.info.username .. '?start).', true)
|
||||||
|
elseif msg.chat.type ~= 'private' then
|
||||||
|
utilities.send_message(self, msg.chat.id, '_Bitte warten, der Administrator meldet sich an..._', true, nil, true)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, twitter_send:do_twitter_authorization_flow(hash), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'auth' and matches[2] then
|
||||||
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if string.len(matches[2]) > 7 then utilities.send_reply(self, msg, 'Invalide PIN!') return end
|
||||||
|
utilities.send_reply(self, msg, twitter_send:get_twitter_access_token(hash, matches[2], oauth_token, oauth_token_secret))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'unauth' then
|
||||||
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
|
if msg.from.id ~= config.admin then
|
||||||
|
utilities.send_reply(self, msg, config.errors.sudo)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
utilities.send_reply(self, msg, twitter_send:reset_twitter_auth(hash), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == 'verify' then
|
||||||
|
local text, pp_url = twitter_send:twitter_verify_credentials(oauth_token, oauth_token_secret)
|
||||||
|
local file = download_to_file(pp_url)
|
||||||
|
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||||
|
utilities.send_reply(self, msg, text)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
|
if not can_send_tweet(msg) then
|
||||||
|
utilities.send_reply(self, msg, '*Du darfst keine Tweets senden.* Entweder wurdest du noch gar nicht freigeschaltet oder ausgeschlossen.', true)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, twitter_send:send_tweet(matches[1], oauth_token, oauth_token_secret, hash), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
utilities.send_reply(self, msg, twitter_send:send_tweet(matches[1], oauth_token, oauth_token_secret, hash), true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return twitter_send
|
@ -1,63 +1,150 @@
|
|||||||
local weather = {}
|
local weather = {}
|
||||||
|
|
||||||
local HTTP = require('socket.http')
|
local HTTPS = require('ssl.https')
|
||||||
|
local URL = require('socket.url')
|
||||||
local JSON = require('dkjson')
|
local JSON = require('dkjson')
|
||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
|
|
||||||
function weather:init(config)
|
function weather:init(config)
|
||||||
if not config.owm_api_key then
|
if not cred_data.forecastio_apikey then
|
||||||
print('Missing config value: owm_api_key.')
|
print('Missing config value: forecastio_apikey.')
|
||||||
|
print('weather.lua will not be enabled.')
|
||||||
|
return
|
||||||
|
elseif not cred_data.google_apikey then
|
||||||
|
print('Missing config value: google_apikey.')
|
||||||
print('weather.lua will not be enabled.')
|
print('weather.lua will not be enabled.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
weather.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
|
weather.triggers = {
|
||||||
weather.doc = [[```
|
"^/wetter$",
|
||||||
]]..config.cmd_pat..[[weather <location>
|
"^/wetter (.*)$",
|
||||||
Returns the current weather conditions for a given location.
|
"^/w$",
|
||||||
```]]
|
"^/w (.*)$"
|
||||||
|
}
|
||||||
|
weather.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[wetter*: Wetter für deinen Wohnort _(/location set [Ort])_
|
||||||
|
*]]..config.cmd_pat..[[wetter* _<Ort>_: Wetter für diesen Ort
|
||||||
|
]]
|
||||||
end
|
end
|
||||||
|
|
||||||
weather.command = 'weather <location>'
|
weather.command = 'wetter'
|
||||||
|
|
||||||
function weather:action(msg, config)
|
local BASE_URL = "https://api.forecast.io/forecast"
|
||||||
|
local apikey = cred_data.forecastio_apikey
|
||||||
|
local google_apikey = cred_data.google_apikey
|
||||||
|
|
||||||
local input = utilities.input(msg.text)
|
function get_city_name(lat, lng)
|
||||||
if not input then
|
local city = redis:hget('telegram:cache:weather:pretty_names', lat..','..lng)
|
||||||
if msg.reply_to_message and msg.reply_to_message.text then
|
if city then return city end
|
||||||
input = msg.reply_to_message.text
|
local url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='..lat..','..lng..'&result_type=political&language=de&key='..google_apikey
|
||||||
|
local res, code = HTTPS.request(url)
|
||||||
|
if code ~= 200 then return 'Unbekannte Stadt' end
|
||||||
|
local data = JSON.decode(res).results[1]
|
||||||
|
local city = data.formatted_address
|
||||||
|
print('Setting '..lat..','..lng..' in redis hash telegram:cache:weather:pretty_names to "'..city..'"')
|
||||||
|
redis:hset('telegram:cache:weather:pretty_names', lat..','..lng, city)
|
||||||
|
return city
|
||||||
|
end
|
||||||
|
|
||||||
|
function weather:get_weather(lat, lng)
|
||||||
|
print('Finde Wetter in '..lat..', '..lng)
|
||||||
|
local text = redis:get('telegram:cache:weather:'..lat..','..lng)
|
||||||
|
if text then print('...aus dem Cache') return text end
|
||||||
|
|
||||||
|
local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=minutely,hourly,daily,alerts,flags'
|
||||||
|
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = url,
|
||||||
|
method = "GET",
|
||||||
|
sink = ltn12.sink.table(response_body)
|
||||||
|
}
|
||||||
|
local ok, response_code, response_headers, response_status_line = HTTPS.request(request_constructor)
|
||||||
|
if not ok then return nil end
|
||||||
|
local data = JSON.decode(table.concat(response_body))
|
||||||
|
local ttl = string.sub(response_headers["cache-control"], 9)
|
||||||
|
|
||||||
|
|
||||||
|
local weather = data.currently
|
||||||
|
local city = get_city_name(lat, lng)
|
||||||
|
local temperature = string.gsub(round(weather.temperature, 1), "%.", ",")
|
||||||
|
local feelslike = string.gsub(round(weather.apparentTemperature, 1), "%.", ",")
|
||||||
|
local temp = '*Wetter in '..city..':*\n'..temperature..' °C'
|
||||||
|
local conditions = ' | '..weather.summary
|
||||||
|
if weather.icon == 'clear-day' then
|
||||||
|
conditions = conditions..' ☀️'
|
||||||
|
elseif weather.icon == 'clear-night' then
|
||||||
|
conditions = conditions..' 🌙'
|
||||||
|
elseif weather.icon == 'rain' then
|
||||||
|
conditions = conditions..' ☔️'
|
||||||
|
elseif weather.icon == 'snow' then
|
||||||
|
conditions = conditions..' ❄️'
|
||||||
|
elseif weather.icon == 'sleet' then
|
||||||
|
conditions = conditions..' 🌨'
|
||||||
|
elseif weather.icon == 'wind' then
|
||||||
|
conditions = conditions..' 💨'
|
||||||
|
elseif weather.icon == 'fog' then
|
||||||
|
conditions = conditions..' 🌫'
|
||||||
|
elseif weather.icon == 'cloudy' then
|
||||||
|
conditions = conditions..' ☁️☁️'
|
||||||
|
elseif weather.icon == 'partly-cloudy-day' then
|
||||||
|
conditions = conditions..' 🌤'
|
||||||
|
elseif weather.icon == 'partly-cloudy-night' then
|
||||||
|
conditions = conditions..' 🌙☁️'
|
||||||
else
|
else
|
||||||
utilities.send_message(self, msg.chat.id, weather.doc, true, msg.message_id, true)
|
conditions = conditions..''
|
||||||
return
|
end
|
||||||
|
local windspeed = ' | 💨 '..string.gsub(round(weather.windSpeed, 1), "%.", ",")..' m/s'
|
||||||
|
|
||||||
|
local text = temp..conditions..windspeed
|
||||||
|
|
||||||
|
if temperature ~= feelslike then
|
||||||
|
text = text..'\n(gefühlt: '..feelslike..' °C)'
|
||||||
|
end
|
||||||
|
|
||||||
|
cache_data('weather', lat..','..lng, text, tonumber(ttl), 'key')
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function weather:action(msg, config, matches)
|
||||||
|
local user_id = msg.from.id
|
||||||
|
|
||||||
|
if matches[1] ~= '/wetter' and matches[1] ~= '/w' then
|
||||||
|
city = matches[1]
|
||||||
|
else
|
||||||
|
local set_location = get_location(user_id)
|
||||||
|
if not set_location then
|
||||||
|
city = 'Berlin, Deutschland'
|
||||||
|
else
|
||||||
|
city = set_location
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local coords = utilities.get_coords(input, config)
|
local lat = redis:hget('telegram:cache:weather:'..string.lower(city), 'lat')
|
||||||
if type(coords) == 'string' then
|
local lng = redis:hget('telegram:cache:weather:'..string.lower(city), 'lng')
|
||||||
utilities.send_reply(self, msg, coords)
|
if not lat and not lng then
|
||||||
|
print('Koordinaten nicht eingespeichert, frage Google...')
|
||||||
|
coords = utilities.get_coords(city, config)
|
||||||
|
lat = coords.lat
|
||||||
|
lng = coords.lon
|
||||||
|
end
|
||||||
|
|
||||||
|
if not lat and not lng then
|
||||||
|
utilities.send_reply(self, msg, '*Diesen Ort gibt es nicht!*', true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon
|
redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat)
|
||||||
|
redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng)
|
||||||
|
|
||||||
local jstr, res = HTTP.request(url)
|
local text = weather:get_weather(lat, lng)
|
||||||
if res ~= 200 then
|
if not text then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
text = 'Konnte das Wetter von dieser Stadt nicht bekommen.'
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
utilities.send_reply(self, msg, text, true)
|
||||||
local jdat = JSON.decode(jstr)
|
|
||||||
if jdat.cod ~= 200 then
|
|
||||||
utilities.send_reply(self, msg, 'Error: City not found.')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
|
||||||
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
|
||||||
local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`'
|
|
||||||
|
|
||||||
utilities.send_reply(self, msg, output, true)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return weather
|
return weather
|
||||||
|
@ -8,10 +8,10 @@ local utilities = require('otouto.utilities')
|
|||||||
wikipedia.command = 'wiki <Begriff>'
|
wikipedia.command = 'wiki <Begriff>'
|
||||||
|
|
||||||
function wikipedia:init(config)
|
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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true).table
|
||||||
wikipedia.doc = [[*
|
wikipedia.doc = [[*
|
||||||
]]..config.cmd_pat..[[wiki* _<Begriff>_: Gibt Wikipedia-Artikel aus
|
]]..config.cmd_pat..[[wiki* _<Begriff>_: Gibt Wikipedia-Artikel aus
|
||||||
Aliase: ]]..config.cmd_pat..[[w, ]]..config.cmd_pat..[[wikipedia]]
|
Alias: ]]..config.cmd_pat..[[wikipedia]]
|
||||||
end
|
end
|
||||||
|
|
||||||
local get_title = function(search)
|
local get_title = function(search)
|
||||||
|
@ -142,9 +142,7 @@ function send_youtube_data(data, msg, self, link, sendpic)
|
|||||||
text = text..'\nACHTUNG, In Deutschland gesperrt!'
|
text = text..'\nACHTUNG, In Deutschland gesperrt!'
|
||||||
end
|
end
|
||||||
local file = download_to_file(image_url)
|
local file = download_to_file(image_url)
|
||||||
bindings.sendPhoto(self, {chat_id = msg.chat.id, reply_to_message_id = msg.message_id, caption = text }, {photo = file} )
|
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||||
os.remove(file)
|
|
||||||
print("Deleted: "..file)
|
|
||||||
else
|
else
|
||||||
utilities.send_reply(self, msg, text, true)
|
utilities.send_reply(self, msg, text, true)
|
||||||
end
|
end
|
||||||
|
@ -17,7 +17,8 @@ function yt_search:init(config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
yt_search.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('yt', true):t('youtube', true).table
|
yt_search.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('yt', true):t('youtube', true).table
|
||||||
yt_search.doc = [[*]]..config.cmd_pat..[[yt* _<Suchbegriff>_: Sucht nach einem YouTube-Video]]
|
yt_search.doc = [[*
|
||||||
|
]]..config.cmd_pat..[[yt* _<Suchbegriff>_: Sucht nach einem YouTube-Video]]
|
||||||
end
|
end
|
||||||
|
|
||||||
local BASE_URL = 'https://www.googleapis.com/youtube/v3'
|
local BASE_URL = 'https://www.googleapis.com/youtube/v3'
|
||||||
|
@ -8,6 +8,8 @@ local ltn12 = require('ltn12')
|
|||||||
local HTTPS = require('ssl.https')
|
local HTTPS = require('ssl.https')
|
||||||
local URL = require('socket.url')
|
local URL = require('socket.url')
|
||||||
local JSON = require('dkjson')
|
local JSON = require('dkjson')
|
||||||
|
local http = require('socket.http')
|
||||||
|
local https = require('ssl.https')
|
||||||
local serpent = require("serpent")
|
local serpent = require("serpent")
|
||||||
local bindings = require('otouto.bindings')
|
local bindings = require('otouto.bindings')
|
||||||
local redis = (loadfile "./otouto/redis.lua")()
|
local redis = (loadfile "./otouto/redis.lua")()
|
||||||
@ -34,6 +36,107 @@ function utilities:send_reply(old_msg, text, use_markdown)
|
|||||||
parse_mode = use_markdown and 'Markdown' or nil
|
parse_mode = use_markdown and 'Markdown' or nil
|
||||||
} )
|
} )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- NOTE: Telegram currently only allows file uploads up to 50 MB
|
||||||
|
-- https://core.telegram.org/bots/api#sendphoto
|
||||||
|
function utilities:send_photo(chat_id, file, text, reply_to_message_id)
|
||||||
|
local output = bindings.request(self, 'sendPhoto', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
caption = text or nil,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
}, {photo = file} )
|
||||||
|
os.remove(file)
|
||||||
|
print("Deleted: "..file)
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- https://core.telegram.org/bots/api#sendaudio
|
||||||
|
function utilities:send_audio(chat_id, file, text, reply_to_message_id, duration, performer, title)
|
||||||
|
local output = bindings.request(self, 'sendAudio', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
caption = text or nil,
|
||||||
|
duration = duration or nil,
|
||||||
|
performer = performer or nil,
|
||||||
|
title = title or nil,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
}, {audio = file} )
|
||||||
|
os.remove(file)
|
||||||
|
print("Deleted: "..file)
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- https://core.telegram.org/bots/api#senddocument
|
||||||
|
function utilities:send_document(chat_id, file, text, reply_to_message_id)
|
||||||
|
local output = bindings.request(self, 'sendDocument', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
caption = text or nil,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
}, {document = file} )
|
||||||
|
os.remove(file)
|
||||||
|
print("Deleted: "..file)
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- https://core.telegram.org/bots/api#sendvideo
|
||||||
|
function utilities:send_video(chat_id, file, text, reply_to_message_id, duration, width, height)
|
||||||
|
local output = bindings.request(self, 'sendVideo', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
caption = text or nil,
|
||||||
|
duration = duration or nil,
|
||||||
|
width = width or nil,
|
||||||
|
height = height or nil,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
}, {video = file} )
|
||||||
|
os.remove(file)
|
||||||
|
print("Deleted: "..file)
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE: Voice messages are .ogg files encoded with OPUS
|
||||||
|
-- https://core.telegram.org/bots/api#sendvoice
|
||||||
|
function utilities:send_voice(chat_id, file, text, reply_to_message_id, duration)
|
||||||
|
local output = bindings.request(self, 'sendVoice', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
duration = duration or nil,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
}, {voice = file} )
|
||||||
|
os.remove(file)
|
||||||
|
print("Deleted: "..file)
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- https://core.telegram.org/bots/api#sendlocation
|
||||||
|
function utilities:send_location(chat_id, latitude, longitude, reply_to_message_id)
|
||||||
|
return bindings.request(self, 'sendLocation', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
latitude = latitude,
|
||||||
|
longitude = longitude,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE: Venue is different from location: it shows information, such as the street adress or
|
||||||
|
-- title of the location with it.
|
||||||
|
-- https://core.telegram.org/bots/api#sendvenue
|
||||||
|
function utilities:send_venue(chat_id, latitude, longitude, reply_to_message_id, title, address)
|
||||||
|
return bindings.request(self, 'sendVenue', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
latitude = latitude,
|
||||||
|
longitude = longitude,
|
||||||
|
title = title,
|
||||||
|
address = address,
|
||||||
|
reply_to_message_id = reply_to_message_id
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- https://core.telegram.org/bots/api#sendchataction
|
||||||
|
function utilities:send_typing(chat_id, action)
|
||||||
|
return bindings.request(self, 'sendChatAction', {
|
||||||
|
chat_id = chat_id,
|
||||||
|
action = action
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
-- get the indexed word in a string
|
-- get the indexed word in a string
|
||||||
function utilities.get_word(s, i)
|
function utilities.get_word(s, i)
|
||||||
s = s or ''
|
s = s or ''
|
||||||
@ -110,6 +213,25 @@ local lc_list = {
|
|||||||
['!'] = 'ǃ'
|
['!'] = 'ǃ'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Retruns true if the string is empty
|
||||||
|
function string:isempty()
|
||||||
|
return self == nil or self == ''
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Retruns true if the string is blank
|
||||||
|
function string:isblank()
|
||||||
|
self = self:trim()
|
||||||
|
return self:isempty()
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_name(msg)
|
||||||
|
local name = msg.from.first_name
|
||||||
|
if name == nil then
|
||||||
|
name = msg.from.id
|
||||||
|
end
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
-- http://www.lua.org/manual/5.2/manual.html#pdf-io.popen
|
-- http://www.lua.org/manual/5.2/manual.html#pdf-io.popen
|
||||||
function run_command(str)
|
function run_command(str)
|
||||||
local cmd = io.popen(str)
|
local cmd = io.popen(str)
|
||||||
@ -118,6 +240,12 @@ function run_command(str)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function convert_timestamp(timestamp, format)
|
||||||
|
local converted_date = run_command('date -d @'..timestamp..' +"'..format..'"')
|
||||||
|
local converted_date = string.gsub(converted_date, '%\n', '')
|
||||||
|
return converted_date
|
||||||
|
end
|
||||||
|
|
||||||
function string.starts(String, Start)
|
function string.starts(String, Start)
|
||||||
return Start == string.sub(String,1,string.len(Start))
|
return Start == string.sub(String,1,string.len(Start))
|
||||||
end
|
end
|
||||||
@ -227,9 +355,9 @@ end
|
|||||||
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
|
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
|
||||||
function utilities.get_coords(input, config)
|
function utilities.get_coords(input, config)
|
||||||
|
|
||||||
local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input)
|
local url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input)
|
||||||
|
|
||||||
local jstr, res = HTTP.request(url)
|
local jstr, res = HTTPS.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
return config.errors.connection
|
return config.errors.connection
|
||||||
end
|
end
|
||||||
@ -461,6 +589,62 @@ utilities.char = {
|
|||||||
em_dash = '—'
|
em_dash = '—'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Returns a table with matches or nil
|
||||||
|
--function match_pattern(pattern, text, lower_case)
|
||||||
|
function match_pattern(pattern, text)
|
||||||
|
if text then
|
||||||
|
local matches = { string.match(text, pattern) }
|
||||||
|
if next(matches) then
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function post_petition(url, arguments, headers)
|
||||||
|
local url, h = string.gsub(url, "http://", "")
|
||||||
|
local url, hs = string.gsub(url, "https://", "")
|
||||||
|
local post_prot = "http"
|
||||||
|
if hs == 1 then
|
||||||
|
post_prot = "https"
|
||||||
|
end
|
||||||
|
local response_body = {}
|
||||||
|
local request_constructor = {
|
||||||
|
url = post_prot..'://'..url,
|
||||||
|
method = "POST",
|
||||||
|
sink = ltn12.sink.table(response_body),
|
||||||
|
headers = headers or {},
|
||||||
|
redirect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local source = arguments
|
||||||
|
if type(arguments) == "table" then
|
||||||
|
local source = helpers.url_encode_arguments(arguments)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not headers then
|
||||||
|
request_constructor.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF8"
|
||||||
|
request_constructor.headers["X-Accept"] = "application/json"
|
||||||
|
request_constructor.headers["Accept"] = "application/json"
|
||||||
|
end
|
||||||
|
request_constructor.headers["Content-Length"] = tostring(#source)
|
||||||
|
request_constructor.source = ltn12.source.string(source)
|
||||||
|
|
||||||
|
if post_prot == "http" then
|
||||||
|
ok, response_code, response_headers, response_status_line = http.request(request_constructor)
|
||||||
|
else
|
||||||
|
ok, response_code, response_headers, response_status_line = https.request(request_constructor)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
response_body = JSON.decode(table.concat(response_body))
|
||||||
|
|
||||||
|
return response_body, response_headers
|
||||||
|
end
|
||||||
|
|
||||||
function get_redis_hash(msg, var)
|
function get_redis_hash(msg, var)
|
||||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||||
return 'chat:'..msg.chat.id..':'..var
|
return 'chat:'..msg.chat.id..':'..var
|
||||||
@ -481,6 +665,14 @@ function tablelength(T)
|
|||||||
return count
|
return count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function round(num, idp)
|
||||||
|
if idp and idp>0 then
|
||||||
|
local mult = 10^idp
|
||||||
|
return math.floor(num * mult + 0.5) / mult
|
||||||
|
end
|
||||||
|
return math.floor(num + 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
function comma_value(amount)
|
function comma_value(amount)
|
||||||
local formatted = amount
|
local formatted = amount
|
||||||
while true do
|
while true do
|
||||||
@ -497,6 +689,16 @@ function string.ends(str, fin)
|
|||||||
return fin=='' or string.sub(str,-string.len(fin)) == fin
|
return fin=='' or string.sub(str,-string.len(fin)) == fin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_location(user_id)
|
||||||
|
local hash = 'user:'..user_id
|
||||||
|
local set_location = redis:hget(hash, 'location')
|
||||||
|
if set_location == 'false' or set_location == nil then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return set_location
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function cache_data(plugin, query, data, timeout, typ)
|
function cache_data(plugin, query, data, timeout, typ)
|
||||||
-- How to: cache_data(pluginname, query_name, data_to_cache, expire_in_seconds)
|
-- How to: cache_data(pluginname, query_name, data_to_cache, expire_in_seconds)
|
||||||
local hash = 'telegram:cache:'..plugin..':'..query
|
local hash = 'telegram:cache:'..plugin..':'..query
|
||||||
@ -619,4 +821,14 @@ function unescape(str)
|
|||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function url_encode(str)
|
||||||
|
if (str) then
|
||||||
|
str = string.gsub (str, "\n", "\r\n")
|
||||||
|
str = string.gsub (str, "([^%w %-%_%.%~])",
|
||||||
|
function (c) return string.format ("%%%02X", string.byte(c)) end)
|
||||||
|
str = string.gsub (str, " ", "+")
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
return utilities
|
return utilities
|
||||||
|
Reference in New Issue
Block a user