commit
061dee2fa2
4
LICENSE
4
LICENSE
@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
|
|||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
{description}
|
{description}
|
||||||
Copyright (C) {year} {fullname}
|
Copyright (C) 2015 Yago Pérez
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -336,4 +336,4 @@ This General Public License does not permit incorporating your program into
|
|||||||
proprietary programs. If your program is a subroutine library, you may
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
consider it more useful to permit linking proprietary applications with the
|
consider it more useful to permit linking proprietary applications with the
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
Public License instead of this License.
|
Public License instead of this License.
|
||||||
|
11
bot/bot.lua
11
bot/bot.lua
@ -1,11 +1,6 @@
|
|||||||
http = require("socket.http")
|
|
||||||
https = require("ssl.https")
|
|
||||||
URL = require("socket.url")
|
|
||||||
json = (loadfile "./libs/JSON.lua")()
|
|
||||||
serpent = (loadfile "./libs/serpent.lua")()
|
|
||||||
require("./bot/utils")
|
require("./bot/utils")
|
||||||
|
|
||||||
VERSION = '0.9.3'
|
VERSION = '0.9.5'
|
||||||
|
|
||||||
function on_msg_receive (msg)
|
function on_msg_receive (msg)
|
||||||
vardump(msg)
|
vardump(msg)
|
||||||
@ -91,7 +86,7 @@ function do_action(msg)
|
|||||||
-- print("Trying", text, "against", pattern)
|
-- print("Trying", text, "against", pattern)
|
||||||
matches = { string.match(text, pattern) }
|
matches = { string.match(text, pattern) }
|
||||||
if matches[1] then
|
if matches[1] then
|
||||||
mark_read(get_receiver(msg), ok_cb, false)
|
mark_read(receiver, ok_cb, false)
|
||||||
print(" matches", pattern)
|
print(" matches", pattern)
|
||||||
if desc.run ~= nil then
|
if desc.run ~= nil then
|
||||||
-- If plugin is for privileged user
|
-- If plugin is for privileged user
|
||||||
@ -230,4 +225,4 @@ end
|
|||||||
-- Start and load values
|
-- Start and load values
|
||||||
our_id = 0
|
our_id = 0
|
||||||
now = os.time()
|
now = os.time()
|
||||||
math.randomseed(now)
|
math.randomseed(now)
|
||||||
|
105
bot/utils.lua
105
bot/utils.lua
@ -1,5 +1,10 @@
|
|||||||
local mimetype = (loadfile "./libs/mimetype.lua")()
|
http = require "socket.http"
|
||||||
local ltn12 = require "ltn12"
|
https = require "ssl.https"
|
||||||
|
ltn12 = require "ltn12"
|
||||||
|
URL = require "socket.url"
|
||||||
|
json = (loadfile "./libs/JSON.lua")()
|
||||||
|
serpent = (loadfile "./libs/serpent.lua")()
|
||||||
|
mimetype = (loadfile "./libs/mimetype.lua")()
|
||||||
|
|
||||||
function get_receiver(msg)
|
function get_receiver(msg)
|
||||||
if msg.to.type == 'user' then
|
if msg.to.type == 'user' then
|
||||||
@ -8,6 +13,9 @@ function get_receiver(msg)
|
|||||||
if msg.to.type == 'chat' then
|
if msg.to.type == 'chat' then
|
||||||
return 'chat#id'..msg.to.id
|
return 'chat#id'..msg.to.id
|
||||||
end
|
end
|
||||||
|
if msg.to.type == 'encr_chat' then
|
||||||
|
return msg.to.print_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function is_chat_msg( msg )
|
function is_chat_msg( msg )
|
||||||
@ -33,11 +41,17 @@ function string:split(sep)
|
|||||||
return fields
|
return fields
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Removes spaces
|
-- DEPRECATED
|
||||||
function string.trim(s)
|
function string.trim(s)
|
||||||
|
print("string.trim(s) is DEPRECATED use string:trim() instead")
|
||||||
return s:gsub("^%s*(.-)%s*$", "%1")
|
return s:gsub("^%s*(.-)%s*$", "%1")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Removes spaces
|
||||||
|
function string:trim()
|
||||||
|
return self:gsub("^%s*(.-)%s*$", "%1")
|
||||||
|
end
|
||||||
|
|
||||||
function get_http_file_name(url, headers)
|
function get_http_file_name(url, headers)
|
||||||
-- Everything after the last /
|
-- Everything after the last /
|
||||||
local file_name = url:match("([^/]+)$")
|
local file_name = url:match("([^/]+)$")
|
||||||
@ -46,7 +60,10 @@ function get_http_file_name(url, headers)
|
|||||||
content_type = content_type or headers["Content-type"]
|
content_type = content_type or headers["Content-type"]
|
||||||
content_type = content_type or h["Content-Type"]
|
content_type = content_type or h["Content-Type"]
|
||||||
|
|
||||||
local extension = mimetype.get_mime_extension(content_type)
|
local extension = nil
|
||||||
|
if content_type then
|
||||||
|
extension = mimetype.get_mime_extension(content_type)
|
||||||
|
end
|
||||||
if extension then
|
if extension then
|
||||||
file_name = file_name.."."..extension
|
file_name = file_name.."."..extension
|
||||||
end
|
end
|
||||||
@ -66,9 +83,24 @@ function download_to_file(url, file_name)
|
|||||||
redirect = true
|
redirect = true
|
||||||
}
|
}
|
||||||
|
|
||||||
local one, c, h = http.request(options)
|
-- nil, code, headers, status
|
||||||
|
local response = nil
|
||||||
|
|
||||||
local file_name = get_http_file_name(url, h)
|
if url:starts('https') then
|
||||||
|
options.redirect = false
|
||||||
|
response = {https.request(options)}
|
||||||
|
else
|
||||||
|
response = {http.request(options)}
|
||||||
|
end
|
||||||
|
|
||||||
|
local code = response[2]
|
||||||
|
local headers = response[3]
|
||||||
|
local status = response[4]
|
||||||
|
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
|
||||||
|
file_name = file_name or get_http_file_name(url, headers)
|
||||||
|
|
||||||
local file_path = "/tmp/"..file_name
|
local file_path = "/tmp/"..file_name
|
||||||
print("Saved to: "..file_path)
|
print("Saved to: "..file_path)
|
||||||
|
|
||||||
@ -135,15 +167,16 @@ function run_command(str)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- User has priviledges
|
||||||
function is_sudo(msg)
|
function is_sudo(msg)
|
||||||
local var = false
|
local var = false
|
||||||
-- Check users id in config
|
-- Check users id in config
|
||||||
for v,user in pairs(_config.sudo_users) do
|
for v,user in pairs(_config.sudo_users) do
|
||||||
if user == msg.from.id then
|
if user == msg.from.id then
|
||||||
var = true
|
var = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return var
|
return var
|
||||||
end
|
end
|
||||||
|
|
||||||
function is_disabled(msg)
|
function is_disabled(msg)
|
||||||
@ -162,11 +195,11 @@ end
|
|||||||
|
|
||||||
-- Returns the name of the sender
|
-- Returns the name of the sender
|
||||||
function get_name(msg)
|
function get_name(msg)
|
||||||
local name = msg.from.first_name
|
local name = msg.from.first_name
|
||||||
if name == nil then
|
if name == nil then
|
||||||
name = msg.from.id
|
name = msg.from.id
|
||||||
end
|
end
|
||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns at table of lua files inside plugins
|
-- Returns at table of lua files inside plugins
|
||||||
@ -214,9 +247,15 @@ function string:isblank()
|
|||||||
return self:isempty()
|
return self:isempty()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns true if String starts with Start
|
-- DEPRECATED!!!!!
|
||||||
function string.starts(String, Start)
|
function string.starts(String, Start)
|
||||||
return Start == string.sub(String,1,string.len(Start))
|
print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead")
|
||||||
|
return Start == string.sub(String,1,string.len(Start))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns true if String starts with Start
|
||||||
|
function string:starts(text)
|
||||||
|
return text == string.sub(self,1,string.len(text))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Send image to user and delete it when finished.
|
-- Send image to user and delete it when finished.
|
||||||
@ -234,9 +273,18 @@ end
|
|||||||
-- Download the image and send to receiver, it will be deleted.
|
-- Download the image and send to receiver, it will be deleted.
|
||||||
-- cb_function and cb_extra are optionals callback
|
-- cb_function and cb_extra are optionals callback
|
||||||
function send_photo_from_url(receiver, url, cb_function, cb_extra)
|
function send_photo_from_url(receiver, url, cb_function, cb_extra)
|
||||||
|
-- If callback not provided
|
||||||
|
cb_function = cb_function or ok_cb
|
||||||
|
cb_extra = cb_extra or false
|
||||||
|
|
||||||
local file_path = download_to_file(url, false)
|
local file_path = download_to_file(url, false)
|
||||||
print("File path: "..file_path)
|
if not file_path then -- Error
|
||||||
_send_photo(receiver, file_path, cb_function, cb_extra)
|
local text = 'Error downloading the image'
|
||||||
|
send_msg(receiver, text, cb_function, cb_extra)
|
||||||
|
else
|
||||||
|
print("File path: "..file_path)
|
||||||
|
_send_photo(receiver, file_path, cb_function, cb_extra)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Same as send_photo_from_url but as callback function
|
-- Same as send_photo_from_url but as callback function
|
||||||
@ -245,8 +293,13 @@ function send_photo_from_url_callback(cb_extra, success, result)
|
|||||||
local url = cb_extra.url
|
local url = cb_extra.url
|
||||||
|
|
||||||
local file_path = download_to_file(url, false)
|
local file_path = download_to_file(url, false)
|
||||||
print("File path: "..file_path)
|
if not file_path then -- Error
|
||||||
_send_photo(receiver, file_path, cb_function, cb_extra)
|
local text = 'Error downloading the image'
|
||||||
|
send_msg(receiver, text, ok_cb, false)
|
||||||
|
else
|
||||||
|
print("File path: "..file_path)
|
||||||
|
_send_photo(receiver, file_path, ok_cb, false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Send multimple images asynchronous.
|
-- Send multimple images asynchronous.
|
||||||
@ -325,4 +378,4 @@ function send_document_from_url(receiver, url, cb_function, cb_extra)
|
|||||||
local file_path = download_to_file(url, false)
|
local file_path = download_to_file(url, false)
|
||||||
print("File path: "..file_path)
|
print("File path: "..file_path)
|
||||||
_send_document(receiver, file_path, cb_function, cb_extra)
|
_send_document(receiver, file_path, cb_function, cb_extra)
|
||||||
end
|
end
|
||||||
|
71
plugins/boobs.lua
Normal file
71
plugins/boobs.lua
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
do
|
||||||
|
|
||||||
|
function getRandomButts(attempt)
|
||||||
|
attempt = attempt or 0
|
||||||
|
attempt = attempt + 1
|
||||||
|
|
||||||
|
local res,status = http.request("http://api.obutts.ru/noise/1")
|
||||||
|
|
||||||
|
if status ~= 200 then return nil end
|
||||||
|
local data = json:decode(res)[1]
|
||||||
|
|
||||||
|
-- The OpenBoobs API sometimes returns an empty array
|
||||||
|
if not data and attempt < 10 then
|
||||||
|
print('Cannot get that butts, trying another ones...')
|
||||||
|
return getRandomButts(attempt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return 'http://media.obutts.ru/' .. data.preview
|
||||||
|
end
|
||||||
|
|
||||||
|
function getRandomBoobs(attempt)
|
||||||
|
attempt = attempt or 0
|
||||||
|
attempt = attempt + 1
|
||||||
|
|
||||||
|
local res,status = http.request("http://api.oboobs.ru/noise/1")
|
||||||
|
|
||||||
|
if status ~= 200 then return nil end
|
||||||
|
local data = json:decode(res)[1]
|
||||||
|
|
||||||
|
-- The OpenBoobs API sometimes returns an empty array
|
||||||
|
if not data and attempt < 10 then
|
||||||
|
print('Cannot get that boobs, trying another ones...')
|
||||||
|
return getRandomBoobs(attempt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return 'http://media.oboobs.ru/' .. data.preview
|
||||||
|
end
|
||||||
|
|
||||||
|
function run(msg, matches)
|
||||||
|
local url = nil
|
||||||
|
|
||||||
|
if matches[1] == "!boobs" then
|
||||||
|
url = getRandomBoobs()
|
||||||
|
end
|
||||||
|
|
||||||
|
if matches[1] == "!butts" then
|
||||||
|
url = getRandomButts()
|
||||||
|
end
|
||||||
|
|
||||||
|
if url ~= nil then
|
||||||
|
local receiver = get_receiver(msg)
|
||||||
|
send_photo_from_url(receiver, url)
|
||||||
|
else
|
||||||
|
return 'Error getting boobs/butts for you, please try again later.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
description = "Gets a random boobs or butts pic",
|
||||||
|
usage = {
|
||||||
|
"!boobs",
|
||||||
|
"!butts"
|
||||||
|
},
|
||||||
|
patterns = {
|
||||||
|
"^!boobs$",
|
||||||
|
"^!butts$"
|
||||||
|
},
|
||||||
|
run = run
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
@ -6,24 +6,40 @@ do
|
|||||||
local BASE_URL = 'http://api.giphy.com/v1'
|
local BASE_URL = 'http://api.giphy.com/v1'
|
||||||
local API_KEY = 'dc6zaTOxFJmzC' -- public beta key
|
local API_KEY = 'dc6zaTOxFJmzC' -- public beta key
|
||||||
|
|
||||||
function get_random_top()
|
function get_image(response)
|
||||||
local res, code = http.request(BASE_URL.."/gifs/trending?api_key="..API_KEY)
|
local images = json:decode(response).data
|
||||||
if code ~= 200 then return nil end
|
if #images == 0 then return nil end -- No images
|
||||||
local images = json:decode(res).data
|
|
||||||
local i = math.random(0,#images)
|
local i = math.random(0,#images)
|
||||||
return images[i].images.downsized.url
|
local image = images[i] -- A random one
|
||||||
|
|
||||||
|
if image.images.downsized then
|
||||||
|
return image.images.downsized.url
|
||||||
|
end
|
||||||
|
|
||||||
|
if image.images.original then
|
||||||
|
return image.original.url
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_random_top()
|
||||||
|
local url = BASE_URL.."/gifs/trending?api_key="..API_KEY
|
||||||
|
local response, code = http.request(url)
|
||||||
|
if code ~= 200 then return nil end
|
||||||
|
return get_image(response)
|
||||||
end
|
end
|
||||||
|
|
||||||
function search(text)
|
function search(text)
|
||||||
local res, code = http.request(BASE_URL.."/gifs/search?q="..text.."&api_key="..API_KEY)
|
text = URL.escape(text)
|
||||||
local images = json:decode(res).data
|
local url = BASE_URL.."/gifs/search?q="..text.."&api_key="..API_KEY
|
||||||
if #images == 0 then return nil end -- No images
|
local response, code = http.request(url)
|
||||||
local i = math.random(0,#images)
|
if code ~= 200 then return nil end
|
||||||
return images[i].images.downsized.url
|
return get_image(response)
|
||||||
end
|
end
|
||||||
|
|
||||||
function run(msg, matches)
|
function run(msg, matches)
|
||||||
local gif_url = ''
|
local gif_url = nil
|
||||||
|
|
||||||
-- If no search data, a random trending GIF will be sended
|
-- If no search data, a random trending GIF will be sended
|
||||||
if matches[1] == "!gif" or matches[1] == "!giphy" then
|
if matches[1] == "!gif" or matches[1] == "!giphy" then
|
||||||
|
@ -22,17 +22,17 @@ function stringlinks(results)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function run(msg, matches)
|
function run(msg, matches)
|
||||||
vardump(matches)
|
vardump(matches)
|
||||||
local results = googlethat(matches[1])
|
local results = googlethat(matches[1])
|
||||||
return stringlinks(results)
|
return stringlinks(results)
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description = "Searches Google and send results",
|
description = "Searches Google and send results",
|
||||||
usage = "!google [terms]: Searches Google and send results",
|
usage = "!google [terms]: Searches Google and send results",
|
||||||
patterns = {
|
patterns = {
|
||||||
"^!google (.*)$",
|
"^!google (.*)$",
|
||||||
"^%.[g|G]oogle (.*)$"
|
"^%.[g|G]oogle (.*)$"
|
||||||
},
|
},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
|
do
|
||||||
|
|
||||||
function run(msg, matches)
|
function run(msg, matches)
|
||||||
return "Hello, " .. matches[1]
|
return "Hello, " .. matches[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description = "Says hello to someone",
|
description = "Says hello to someone",
|
||||||
usage = "say hello to [name]",
|
usage = "say hello to [name]",
|
||||||
patterns = {
|
patterns = {
|
||||||
"^say hello to (.*)$",
|
"^say hello to (.*)$",
|
||||||
"^Say hello to (.*)$"
|
"^Say hello to (.*)$"
|
||||||
},
|
},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end
|
@ -61,14 +61,14 @@ function run(msg, matches)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description = "Help plugin. Get info from other plugins. ",
|
description = "Help plugin. Get info from other plugins. ",
|
||||||
usage = {
|
usage = {
|
||||||
"!help: Show all the help",
|
"!help: Show all the help",
|
||||||
"!help md: Generate a GitHub Markdown table"
|
"!help md: Generate a GitHub Markdown table"
|
||||||
},
|
},
|
||||||
patterns = {
|
patterns = {
|
||||||
"^!help$",
|
"^!help$",
|
||||||
"^!help md$"
|
"^!help md$"
|
||||||
},
|
},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
@ -10,11 +10,11 @@ return {
|
|||||||
description = "When user sends image URL (ends with png, jpg, jpeg) download and send it to origin.",
|
description = "When user sends image URL (ends with png, jpg, jpeg) download and send it to origin.",
|
||||||
usage = "",
|
usage = "",
|
||||||
patterns = {
|
patterns = {
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.png)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.png)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.jpg)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.jpg)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.jpeg)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.jpeg)$",
|
||||||
},
|
},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -26,10 +26,10 @@ function run(msg, matches)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description = "Search image with Google API and sends it.",
|
description = "Search image with Google API and sends it.",
|
||||||
usage = "!img [term]: Random search an image with Google API.",
|
usage = "!img [term]: Random search an image with Google API.",
|
||||||
patterns = {"^!img (.*)$"},
|
patterns = {"^!img (.*)$"},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
||||||
|
|
||||||
end
|
end
|
@ -1,23 +1,26 @@
|
|||||||
|
do
|
||||||
|
|
||||||
function run(msg, matches)
|
function run(msg, matches)
|
||||||
file = download_to_file(matches[1])
|
file = download_to_file(matches[1])
|
||||||
send_document(get_receiver(msg), file, ok_cb, false)
|
send_document(get_receiver(msg), file, ok_cb, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description = "When user sends media URL (ends with gif, mp4, pdf, etc.) download and send it to origin.",
|
description = "When user sends media URL (ends with gif, mp4, pdf, etc.) download and send it to origin.",
|
||||||
usage = "",
|
usage = "",
|
||||||
patterns = {
|
patterns = {
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.gif)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.gif)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.mp4)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.mp4)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.pdf)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.pdf)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.ogg)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.ogg)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.zip)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.zip)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.mp3)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.mp3)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.rar)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.rar)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.wmv)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.wmv)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.doc)$",
|
"(https?://[%w-_%.%?%.:/%+=&]+%.doc)$",
|
||||||
"(https?://[%w-_%.%?%.:/%+=&]+.avi)$"
|
"(https?://[%w-_%.%?%.:/%+=&]+%.avi)$"
|
||||||
},
|
},
|
||||||
run = run
|
run = run
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end
|
@ -44,7 +44,7 @@ end
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
description = "Send comic images from xkcd",
|
description = "Send comic images from xkcd",
|
||||||
usage = {"!xkcd (id): Send an xkcd image and tigle. If not id, send a random one"},
|
usage = {"!xkcd (id): Send an xkcd image and title. If not id, send a random one"},
|
||||||
patterns = {
|
patterns = {
|
||||||
"^!xkcd$",
|
"^!xkcd$",
|
||||||
"^!xkcd (%d+)",
|
"^!xkcd (%d+)",
|
||||||
|
Reference in New Issue
Block a user