Skip to content
neersighted edited this page Apr 27, 2012 · 68 revisions

Writing Plugins

Writing plugins for CloudBot is simple! This page seeks to detail all you need to know to write your own plugins.

(We'd also love it if you helped give back to CloudBot! Send us your custom plugins for inclusion!)

Learning by example

plugins/echo.py:

from util import hook

@hook.command
def echo(inp):
    return inp + inp

usage:

<Luke> .echo dance
<MyNewCloudBot> (Luke) dancedance

explanation:

This defines a command that replies with twice its input. It can be invoked by saying phrases in a channel the bot is in, notably ".echo", "MyNewCloudBot: echo", "MyNewCloudBot; echo", and "MyNewCloudBot, echo" (assuming the bot's nick is "MyNewCloudBot").

It is important to note that any output a command returns will be printed in the channel the command was used in. Of course, you don't need to use return as you can just use one of the functions detailed near the bottom of this page.

CloudBot continually scans the ./plugins directory for new or changed .py files. When it finds one, it runs it and examines each function to see whether it is a plugin. If it is, the plugin is loaded.

The decorators found in util/hook.py mark functions as plugins of various types.

Plugin hooks

There are four types of plugin hooks: commands, regexes, events, and sieves. The hook type is assigned to plugin functions using decorators found in util/hook.py.

All plugins need 'from util import hook' if they want to be callable.

There is also a secondary hook decorator: @hook.singlethread. It indicates that the function should run in its own thread. Note that, in that case, you can't use the existing database connection object.

@hook.command

@hook.command @hook.command(mycommand)

Commands run when the beginning of a normal chat line matches one of .command, botnick: command, botnick; command, or botnick, command, where command is the command name, and botnick is the bot's nick on the server.

Commands respond to abbreviated forms: a command named "dictionary" will be invoked on both ".dictionary" and ".dict". If an abbreviated command is ambiguous, the bot will return with a list of possibilities: given commands "dictionary" and "dice", attempting to run command ".di" will make the bot say "did you mean dictionary or dice?".

When @hook.command is used without arguments, the command name is set to the function name. When given an argument, it is used as the command name. This allows one function to respond to multiple commands:

The first argument, inp, will be the text that occurs after the command. (e.g., "bar" in ".foo bar"). You can split this with inp.split(" ").

from util import hook

@hook.command('hi')
@hook.command
def hello(inp):
    return "Hey there!"

Users can invoke this function with either ".hello" or ".hi".

If a plugin does not take arguments, or arguments are optional, add autohelp=False to avoid the automatic help message. ie:

@hook.command('hi', autohelp=False)

@hook.regex

@hook.regex @hook.regex(myregex)

Takes an argument corresponding to the regex string (not the compiled regex), followed by optional flags. Each line of chat is matched against the provided regex pattern; if it finds a matc, the hooked function will be called with the match object.

@hook.event

@hook.event @hook.event(myevent)

Event hooks are called whenever a specific IRC command is issued. For example, to run some code whenever a user talks, you can use 'PRIVMSG' as the argument. Using '*' as the argument will hook all IRC activity.

Some useful events to hook onto are:

  • PRIVMSG - called when a user speaks
  • KICK - called when a user is kicked
  • NICK - called when a user changes nick
  • 004 - called when the bot is connected to the network and ready to accept input

The first argument returned for 'PRIVMSG' be a two-element list of the form ["#channel", "text"]. Details on what other types of event return will be added soon.

More hook info:

If a hook should only work for admins, add adminonly=True to the hook (not the function) to restrict it. ie:

@hook.command('hi', adminonly=True)

If a hook should not show help when used without arguments, add autohelp=False to the hook (not the function). ie:

@hook.command('hi', autohelp=True)

useful arguments:

These arguments are shared by functions of all hook types:

  • inp -- the command arguments.
  • nick -- string, the nickname of whoever sent the message.
  • channel -- string, the channel the message was sent on. Equal to nick if it's a private message.
  • msg -- string, the line that was sent.
  • raw -- string, the raw full line that was sent.
  • re -- the result of doing re.match(hook, msg).
  • input -- the triggering line of text.
  • bot -- the running bot object.
  • db -- the database connection object.

useful functions:

  • say(msg): obvious (Luke! Want to dance?)
  • me(action): makes the bot act something out (* MyNewCloudBot dances with Luke!)
  • reply(msg): makes the bot say something with the name of the user who triggered the hook ((Luke) That was fun!) )
  • msg(target, msg): sends msg to target (MyNewCloudBot => Luke: Psst, let's do it again!)
  • (other irc commands, like mode, topic, etc)

In order to use these, you must pass them as a Nonetype argument to your command, like so:

from util import hook
@hook.command
def say_something(inp, say=None, me=None, nick=None)
    me("is going to say something that " + nick + " told me to say!")
    say(inp)

usage:

<Luke> .say_something I love to dance! :D
* MyNewCloudBot is going to say something that Luke told him to say!
<MyNewCloudBot> I love to dance! :D

(these must me used as arguments to the plugin, not the hook itself)

Getting Help

If you need help with anything on this page, head on over to #CloudBot!

Clone this wiki locally