This repository has been archived on 2021-04-24. You can view files and clone it, but cannot push or open issues or pull requests.
Mikubot-2/README.md
2016-09-09 05:01:38 -04:00

566 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# otouto
The plugin-wielding, multipurpose Telegram bot.
[Public Bot](http://telegram.me/mokubot) |
[Official Channel](http://telegram.me/otouto) |
[Bot Development Group](http://telegram.me/BotDevelopment)
otouto is a plugin-based, IRC-style bot written in Lua for the
[Telegram Bot API](http://core.telegram.org/bots/api).
otouto (including all plugins and documentation) is free software; you are free
to redistribute it and/or modify it under the terms of the GNU Affero General
Public License, version 3. See **LICENSE** for details.
**The Manual**
| For Users | For Coders |
|:----------------------------------------------|:------------------------------|
| [Setup](#setup) | [Plugins](#plugins) |
| [Configuration](#configuration) | [Bindings](#bindings) |
| [Control plugins](#control-plugins) | [Database](#database) |
| [Group administration](#group-administration) | [Output style](#output-style) |
| [List of plugins](#list-of-plugins) | [Contributors](#contributors) |
## Setup
To get your bot running as soon as possible, see [Quick start](#quick-start).
otouto uses Lua (5.3 is recommended) and the following Lua libraries: luasocket,
luasec, multipart-post, dkjson, and lpeg. If you are using Lua 5.2, luautf8 is
also required. It is recommended you install these with Luarocks. This can be
done easily on Ubuntu with the `install-dependencies.sh` script.
To get started, clone the repository and set the following values in
`config.lua`:
- `bot_api_key` as your bot authentication token from the BotFather.
- `admin` as your Telegram ID.
Some plugins are not enabled by default. If you wish to enable them, add their
names (sans file extension) to the `plugins` table in the configuration file.
When you are ready to start the bot, run the `launch.sh` script. This script
will automatically restart the bot five seconds after being stopped. If this
behavior is undesired, start the bot manually with `lua main.lua`.
To stop the bot, send "/halt" through Telegram. You can exit with Ctrl-C (or two
Ctrl-C if using `launch.sh`), but this is not recommended as it risks data loss.
Note that certain plugins, such as `translate.lua` and `greetings.lua`, will
require privacy mode to be disabled. Additionally, some plugins may require or
make use of various API keys and/or other configuration values not set by
default. See [Configuration](#configuration) for details.
### Quick start
1. Clone the repository.
`git clone http://otou.to/code otouto`
2. Install dependencies: Lua and the following Lua libs: luasocket, luasec,
multipart-post, dkjson, and lpeg.†
3. Add your bot token and Telegram ID to `config.lua`.
4. Start the bot with `./launch.sh`.
**†** On Ubuntu, this can be done easily with the `install-dependencies.sh`
script.
## Configuration
otouto is configured in the `config.lua` file. It is the single point of
configuration for the bot, and contains any necessary user-specific variables,
such as API keys, custom error messages, and enabled plugins.
This section includes an exhaustive list of possible configuration values for
otouto and official plugins.
### Bot configuration values
| Name | Default | Description |
|:--------------|:--------|:---------------------------------------------------|
| `bot_api_key` | nil | Telegram bot API token. |
| `admin` | nil | Telegram ID of the bot owner. |
| `log_chat` | nil | Telegram ID of the recipient for error messages. |
| `cmd_pat` | `"/"` | Character (or string) to be used for bot commands. |
| `lang` | `"en"` | Two-letter ISO 639-1 language code. |
| `about_text` | ... | Informational text to be returned by /about. |
#### Error messages
These are the generic error messages used by most plugins. These belong in a
table named `errors`.
| Name | Default |
|:-------------|:----------------------------------|
| `generic` | `"An unexpected error occurred."` |
| `connection` | `"Connection error."` |
| `results` | `"No results found."` |
| `argument` | `"Invalid argument."` |
| `syntax` | `"Invalid syntax."` |
#### Plugins table
This table is an array of the names of enabled plugins. To enable a plugin, add
its name to the list.
### Plugin configuration values
| Name | Description
|:--------------------------|:--------------------------------------------------------------------------------------------|
| `google_api_key` | [Google API](http://console.developers.google.com) key for `gImages.lua` and `youtube.lua`. |
| `google_cse_key` | [Google CSE](http://cse.google.com/cse) key for `gImages.lua`. |
| `lastfm_api_key` | [last.fm API](http://last.fm/api) key for `lastfm.lua`. |
| `owm_api_key` | [OpenWeatherMap API](http://openweathermap.org/API) key for `weather.lua`. |
| `biblia_api_key` | [Biblia API](http://api.biblia.com) key for `bible.lua`. |
| `thecatapi_key` | [The Cat API](http://thecatapi.com) key for `cats.lua` (optional). |
| `nasa_api_key` | [NASA API](http://api.nasa.gov) key for the `apod.lua` (optional). |
| `yandex_key` | [Yandex API](http://tech.yandex.com/keys/get) key for `translate.lua`. |
| `bing_api_key` | [Bing Search API](http://datamarket.azure.com/dataset/bing/search) key for `bing.lua`. |
| `drua_block_on_blacklist` | Whether to block blacklisted users, if tg-cli is in use. |
| `cli_port` | The port to use for tg connections. |
| `hackernews_interval` | The lifespan, in minutes, for each set of results hackernews.lua before refreshing. |
| `hackernews_onstart` | Whether hackernews.lua should fetch articles at load (rather than waiting for demand). |
Some plugins have many configuration values which warrant their own section of
the configuration file. That section will be the name of the plugin, without the
file extension. They are listed below.
#### remind.lua
| Name | Default | Description |
|:------------------------|:---------|:---------------------------------------------------------|
| `persist` | `true` | Whether reminders should be saved if they fail for send. |
| `max_length` | `1000` | The maximum length for reminders, in bytes. |
| `max_duration` | `526000` | The maximum duration of a reminder, in minutes. |
| `max_reminders_group` | `10` | The maximum number of reminders for a group. |
| `max_reminders_private` | `50` | The maximum number of reminders in private. |
#### chatter.lua
| Name | Default | Description |
|:----------------|:-------------------------------------------|:-------------------------------------------------------------------------|
| `cleverbot_api` | `"https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text="` | Cleverbot API endpoint used by `cleverbot.lua`. |
| `connection` | `"I don't feel like talking right now."` | Generic response for connection errors. |
| `response` | `"I don't know what to say to that."` | Generic response for when the API has no response. |
#### greetings.lua
The `greetings` table is a list of custom responses for the greetings plugin.
Each value is an array of triggers, and the key for that array is the response.
The default values are inserted by the greetings plugin if there is no user
configuration. In the responses, `#NAME` is replaced with the user's name or
nickname. The bot's name is automatically appended to all triggers. Triggers are
not case sensitive.
#### reactions.lua
The `reactions` table is also a list of custom responses, for the reactions
plugin. Each value is a key/value pair, where the key is the trigger, and the
value is the reaction. The reactions plugin differs from the greetings plugin by
how it is triggered: A reaction command must be at the beginning or end of a
line. Reactions may be formatted with HTML. Configuration values should be
pre-escaped.
## Control plugins
Some plugins are designed to be used by the bot's owner. Here are some examples,
how they're used, and what they do.
| Plugin | Command | Function |
|:----------------|:-----------|:---------------------------------------------------|
| `control.lua` | /reload | Reloads all plugins and configuration. |
| | /halt | Shuts down the bot after saving the database. |
| | /script | Runs a list a bot commands, separated by newlines. |
| `blacklist.lua` | /blacklist | Blocks people from using the bot. |
| `shell.lua` | /run | Executes shell commands on the host system. |
| `luarun.lua` | /lua | Executes Lua commands in the bot's environment. |
## Group Administration
The administration plugin enables self-hosted, single-realm group
administration, supporting both normal groups and supergroups whch are owned by
the bot owner. This works by sending TCP commands to an instance of tg running
on the owner's account.
To get started, compile the `test` branch of
[tg-cli](http://github.com/vysheng/tg). On Ubuntu and Debian, this can be done
easily with the `tg-install.sh` script.
Once the compilation is finished, enable the `administration` plugin in your
config file. You may have reason to change the default TCP port (4567); if that
is the case, remember to change it in `tg-launch.sh` as well. Run
`./tg-launch.sh` in a separate screen/tmux window. You'll have to enter your
phone number and go through the login process the first time. The script is set
to restart tg after two seconds, so you'll need to Ctrl+C after exiting.
While tg is running, you may start/reload otouto with `administration.lua`
enabled, and have access to a wide variety of administrative commands and
automata. The administration "database" is stored in `administration.json`. To
start using otouto to administrate a group (note that you must be the owner (or
an administrator)), send `/gadd` to that group. For a list of commands, use
`/ahelp`. Below I'll describe various functions now available to you.
| Command | Function | Privilege | Internal? |
|:------------|:------------------------------------------------|:----------|:----------|
| /groups | Returns a list of administrated groups (except the unlisted). | 1 | N |
| /ahelp | Returns a list of accessible administrative commands. | 1 | Y |
| /ops | Returns a list of the moderators and governor of a group. | 1 | Y |
| /desc | Returns detailed information for a group. | 1 | Y |
| /rules | Returns the rules of a group. | 1 | Y |
| /motd | Returns the message of the day of a group. | 1 | Y |
| /link | Returns the link for a group. | 1 | Y |
| /kick | Removes the target from the group. | 2 | Y |
| /ban | Bans the target from the group. | 2 | Y |
| /unban | Unbans the target from the group. | 2 | Y |
| /setmotd | Sets the message of the day for a group. | 2 | Y |
| /changerule | Changes an individual group rule. | 3 | Y |
| /setrules | Sets the rules for a group. | 3 | Y |
| /setlink | Sets the link for a group. | 3 | Y |
| /alist | Returns a list of administrators. | 3 | Y |
| /flags | Returns a list of flags and their states, or toggles one. | 3 | Y |
| /antiflood | Configures antiflood (flag 5) settings. | 3 | Y |
| /mod | Promotes a user to a moderator. | 3 | Y |
| /demod | Demotes a moderator to a user. | 3 | Y |
| /gov | Promotes a user to the governor. | 4 | Y |
| /degov | Demotes the governor to a user. | 4 | Y |
| /hammer | Blacklists and globally bans a user. | 4 | N |
| /unhammer | Unblacklists and globally bans a user. | 4 | N |
| /admin | Promotes a user to an administrator. | 5 | N |
| /deadmin | Demotes an administrator to a user. | 5 | N |
| /gadd | Adds a group to the administrative system. | 5 | N |
| /grem | Removes a group from the administrative system. | 5 | Y |
| /glist | Returns a list of all administrated groups and their governors. | 5 | N |
Internal commands can only be run within an administrated group.
### Description of Privileges
| | Title | Description | Scope |
|:-:|:--------------|:------------------------------------------------------------------|:-------|
| 0 | Banned | Cannot enter the group(s). | Either |
| 1 | User | Default rank. | Local |
| 2 | Moderator | Can kick/ban/unban users. Can set MOTD. | Local |
| 3 | Governor | Can set rules/link, promote/demote moderators, modify flags. | Local |
| 4 | Administrator | Can globally ban/unban users, promote/demote governors. | Global |
| 5 | Owner | Can add/remove groups, broadcast, promote/demote administrators. | Global |
Obviously, each greater rank inherits the privileges of the lower, positive
ranks.
### Flags
| | Name | Description |
|:-:|:------------|:---------------------------------------------------------------------------------|
| 1 | unlisted | Removes a group from the /groups listing. |
| 2 | antisquig | Automatically removes users for posting Arabic script or RTL characters. |
| 3 | antisquig++ | Automatically removes users whose names contain Arabic script or RTL characters. |
| 4 | antibot | Prevents bots from being added by non-moderators. |
| 5 | antiflood | Prevents flooding by rate-limiting messages per user. |
| 6 | antihammer | Allows globally-banned users to enter a group. |
#### antiflood
antiflood (flag 5) provides a system of automatic flood protection by removing
users who post too much. It is entirely configurable by a group's governor, an
administrator, or the bot owner. For each message to a particular group, a user
is awarded a certain number of "points". The number of points is different for
each message type. When the user reaches 100 points, he is removed. Points are
reset each minute. In this way, if a user posts twenty messages within one
minute, he is removed.
**Default antiflood values:**
| Type | Points |
|:-----|:------:|
| text | 5 |
| contact | 5 |
| audio | 5 |
| voice | 5 |
| photo | 10 |
| document | 10 |
| location | 10 |
| video | 10 |
| sticker | 20 |
Additionally, antiflood can be configured to automatically ban a user after he
has been automatically kicked from a single group a certain number of times in
one day. This is configurable as the antiflood value `autoban` and is set to
three by default.
## List of plugins
| Plugin | Command | Function | Aliases |
|:----------------------|:------------------------------|:----------------------------------------------------------|:--------|
| `help.lua` | /help [command] | Returns a list of commands or command-specific help. | /h |
| `about.lua` | /about | Returns the about text as configured in config.lua. |
| `ping.lua` | /ping | The simplest plugin ever! |
| `echo.lua` | /echo text | Repeats a string of text. |
| `bing.lua` | /bing query | Returns Bing web results. | /g |
| `gImages.lua` | /images query | Returns a Google image result. | /i |
| `gMaps.lua` | /location query | Returns location data from Google Maps. | /loc |
| `youtube.lua` | /youtube query | Returns the top video result from YouTube. | /yt |
| `wikipedia.lua` | /wikipedia query | Returns the summary of a Wikipedia article. | /w |
| `lastfm.lua` | /np [username] | Returns the song you are currently listening to. |
| `lastfm.lua` | /fmset [username] | Sets your username for /np. /fmset -- will delete it. |
| `hackernews.lua` | /hackernews | Returns the latest posts from Hacker News. | /hn |
| `imdb.lua` | /imdb query | Returns film information from IMDb. |
| `hearthstone.lua` | /hearthstone query | Returns data for Hearthstone cards matching the query. | /hs |
| `calc.lua` | /calc expression | Returns conversions and solutions to math expressions. |
| `bible.lua` | /bible reference | Returns a Bible verse. | /b |
| `urbandictionary.lua` | /urban query | Returns the top definition from Urban Dictionary. | /ud |
| `time.lua` | /time query | Returns the time, date, and a timezone for a location. |
| `weather.lua` | /weather query | Returns current weather conditions for a given location. |
| `nick.lua` | /nick nickname | Set your nickname. /nick - will delete it. |
| `whoami.lua` | /whoami | Returns user and chat info for you or the replied-to user. | /who |
| `eightball.lua` | /8ball | Returns an answer from a magic 8-ball. |
| `dice.lua` | /roll nDr | Returns RNG dice rolls. Uses D&D notation. |
| `reddit.lua` | /reddit [r/subreddit ¦ query] | Returns the top results from a subreddit, query, or r/all. | /r |
| `xkcd.lua` | /xkcd [query] | Returns an xkcd strip and its alt text. |
| `slap.lua` | /slap target | Gives someone a slap (or worse). |
| `commit.lua` | /commit | Returns a commit message from whatthecommit.com. |
| `fortune.lua` | /fortune | Returns a UNIX fortune. |
| `pun.lua` | /pun | Returns a pun. |
| `pokedex.lua` | /pokedex query | Returns a Pokedex entry. | /dex |
| `currency.lua` | /cash [amount] cur to cur | Converts one currency to another. |
| `cats.lua` | /cat | Returns a cat picture. |
| `reactions.lua` | /reactions | Returns a list of emoticons which can be posted by the bot. |
| `apod.lua` | /apod [date] | Returns the NASA Astronomy Picture of the Day. |
| `dilbert.lua` | /dilbert [date] | Returns a Dilbert strip. |
| `patterns.lua` | /s/from/to/ | Search-and-replace using Lua patterns. |
| `me.lua` | /me | Returns user-specific data stored by the bot. |
| `remind.lua` | /remind duration message | Reminds a user of something after a duration of minutes. |
| `channel.lua` | /ch channel \n message | Sends a markdown-enabled message to a channel. |
| `isup.lua` | /isup url | Returns the status of a website. |
| `starwars-crawl.lua` | /sw title ¦ number | Returns the opening crawl from the specified Star Wars film. | /sw |
| `chuckfact.lua` | /chuck | Returns a fact about Chuck Norris. | /cn |
| `catfact.lua` | /catfact | Returns a fact about cats. |
## Plugins
otouto uses a robust plugin system, similar to yagop's
[Telegram-Bot](http://github.com/yagop/telegram-bot).
Most plugins are intended for public use, but a few are for other purposes, like
those for [use by the bot's owner](#control-plugins). See
[here](#list-of-plugins) for a list of plugins.
There are five standard plugin components.
| Component | Description |
|:------------|:---------------------------------------------------------------|
| `action` | Main function. Expects `msg` table as an argument. |
| `triggers` | Table of triggers for the plugin. Uses Lua patterns. |
| `init` | Optional function run when the plugin is loaded. |
| `cron` | Optional function to be called every minute. |
| `command` | Basic command and syntax. Listed in the help text. |
| `doc` | Usage for the plugin. Returned by "/help $command". |
| `error` | Plugin-specific error message; false for no message. |
| `panoptic` | True if plugin should see all messages. (See below.) |
| `help_word` | Keyword for command-specific help. Generated if absent. |
No component is required, but some depend on others. For example, `action` will
never be run if there's no `triggers`, and `doc` will never be seen if there's
no `command`.
If a plugin's `action` returns `true`, `on_msg_receive` will continue its loop.
When an action or cron function fails, the exception is caught and passed to the
`handle_exception` utilty and is either printed to the console or send to the
chat/channel defined in `log_chat` in config.lua.
The `panoptic` value is a boolean (or nil; its absence means false) to state
whether the plugin should be included in the `panoptic_plugins` table. Plugins
in this table are the only plugins whose triggers are checked against a
message's text if that message is forwarded or from a blacklisted user.
Interactions with the bot API are straightforward. See the
[Bindings section](#bindings) for details.
Several functions used in multiple plugins are defined in utilities.lua. Refer
to that file for usage and documentation.
## Bindings
Calls to the Telegram bot API are performed with the `bindings.lua` file through
the multipart-post library. otouto's bindings file supports all standard API
methods and all arguments. Its main function, `bindings.request`, accepts three
arguments: `method`, `parameters`, `file`. Before using it, initialize the
bindings module with its `init` function, passing your bot token as the
argument.
`method` is the name of the API method. `parameters` (optional) is a table of
key/value pairs of the method's parameters to be sent with the method. `file`
(super optional) is a table of a single key/value pair, where the key is the
name of the parameter and the value is the filename (if these are included in
`parameters` instead, otouto will attempt to send the filename as a file ID).
Additionally, any method can be called as a key in the `bindings` table
(for example, `bindings.getMe`). The `bindings.gen` function (which is also the
`__index` function in its metatable) will forward its arguments to
`bindings.request` in their proper form. In this way, the following two function
calls are equivalent:
```lua
bindings.request(
'sendMessage',
{
chat_id = 987654321,
text = 'Quick brown fox.',
reply_to_message_id = 54321,
disable_web_page_preview = false,
parse_method = 'Markdown'
}
)
bindings.sendMessage{
chat_id = 987654321,
text = 'Quick brown fox.',
reply_to_message_id = 54321,
disable_web_page_preview = false,
parse_method = 'Markdown'
}
```
Furthermore, `utilities.lua` provides two "shortcut" functions to mimic the
behavior of otouto's old bindings: `send_message` and `send_reply`.
`send_message` accepts these arguments: `self`, `chat_id`, `text`,
`disable_web_page_preview`, `reply_to_message_id`, `use_markdown`. The following
function call is equivalent to the two above:
```lua
utilities.send_message(987654321, 'Quick brown fox.', false, 54321, true)
```
Uploading a file for the `sendPhoto` method would look like this:
```lua
bindings.sendPhoto({ chat_id = 987654321 }, { photo = 'dankmeme.jpg' } )
```
and using `sendPhoto` with a file ID would look like this:
```lua
bindings.sendPhoto{
chat_id = 987654321,
photo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'
}
```
Upon success, bindings will return the deserialized result from the API. Upon
failure, it will return false and the result. In the case of a connection error,
it will return two false values. If an invalid method name is given, bindings
will throw an exception. This is to mimic the behavior of more conventional
bindings as well as to prevent "silent errors".
## Database
otouto doesn't use one. This isn't because of dedication to lightweightedness or
some clever design choice. Interfacing with databases through Lua is never a
simple, easy-to-learn process. As one of the goals of otouto is that it should
be a bot which is easy to write plugins for, our approach to storing data is to
treat our datastore like any ordinary Lua data structure. The "database" is a
table accessible in the `database` value of the bot instance (usually
`self.database`), and is saved as a JSON-encoded plaintext file each hour, or
when the bot is told to halt. This way, keeping and interacting with persistent
data is no different than interacting with a Lua table -- with one exception:
Keys in tables used as associative arrays must not be numbers. If the index keys
are too sparse, the JSON encoder/decoder will either change them to keys or
throw an error.
Alone, the database will have this structure:
```lua
{
users = {
["55994550"] = {
id = 55994550,
first_name = "Drew",
username = "topkecleon"
}
},
userdata = {
["55994550"] = {
nickname = "Worst coder ever",
lastfm = "topkecleon"
}
},
version = "3.11"
}
```
`database.users` will store user information (usernames, IDs, etc) when the bot
sees the user. Each table's key is the user's ID as a string.
`database.userdata` is meant to store miscellanea from various plugins.
`database.version` stores the last bot version that used it. This is to simplify
migration to the next version of the bot an easy, automatic process.
Data from other plugins is usually saved in a table with the same name of that
plugin. For example, administration.lua stores data in
`database.administration`.
## Output style
otouto plugins should maintain a consistent visual style in their output. This
provides a recognizable and comfortable user experience.
### Titles
Title lines should be **bold**, including any names and trailing punctuation
(such as colons). The exception to this rule is if the title line includes a
query, which should be _italic_. It is also acceptable to have a link somewhere
inside a title, usually within parentheses. eg:
> **Star Wars: Episode IV - A New Hope (1977)**
>
> **Search results for** _star wars_**:**
>
> **Changelog for otouto (**[Github](http://github.com/topkecleon/otouto)**):**
### Lists
Numerated lists should be done with the number and its following punctuation
bolded. Unnumbered lists should use the bullet character ( • ). eg:
> **1.** Life as a quick brown fox.
>
> **2.** The art of jumping over lazy dogs.
and
> • Life as a quick brown fox.
>
> • The art of jumping over lazy dogs.
### Links
Always name your links. Even then, use them with discretion. Excessive links
make a post look messy. Links are reasonable when a user may want to learn more
about something, but should be avoided when all desirable information is
provided. One appropriate use of linking is to provide a preview of an image, as
xkcd.lua and apod.lua do.
### Other Stuff
User IDs should appear within brackets, monospaced (`[123456789]`). Descriptions
and information should be in plain text, but "flavor" text should be italic. The
standard size for arbitrary lists (such as search results) is eight within a
private conversation and four elsewhere. This is a trivial pair of numbers
(leftover from the deprecated Google search API), but consistency is noticeable
and desirable.
## Contributors
Everybody is free to contribute to otouto. If you are interested, you are
invited to [fork the repo](http://github.com/topkecleon/otouto/fork) and start
making pull requests. If you have an idea and you are not sure how to implement
it, open an issue or bring it up in the
[Bot Development group](http://telegram.me/BotDevelopment).
The creator and maintainer of otouto is
[topkecleon](http://github.com/topkecleon). He can be contacted via
[Telegram](http://telegram.me/topkecleon),
[Twitter](http://twitter.com/topkecleon), or [email](mailto:drew@otou.to).
[List of contributors.](https://github.com/topkecleon/otouto/graphs/contributors)
There are a a few ways to contribute if you are not a programmer. For one, your
feedback is always appreciated. Drop me a line on Telegram or on Twitter.
Secondly, we are always looking for new ideas for plugins. Most new plugins
start with community input. Feel free to suggest them on Github or in the Bot
Dev group. You can also donate Bitcoin to the following address:
`1BxegZJ73hPu218UrtiY8druC7LwLr82gS`
Contributions are appreciated in all forms. Monetary contributions will go
toward server costs. Donators will be eternally honored (at their discretion) on
this page.
| Donators (in chronological order) |
|:----------------------------------------------|
| [n8 c00](http://telegram.me/n8_c00) |
| [Alex](http://telegram.me/sandu) |
| [Brayden](http://telegram.me/bb010g) |
| [Milad](http://telegram.me/thelad) |