Skip to content
lukeroge edited this page May 6, 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.

Command Hook

@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:

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" (note that they will have to add (junk) arguments, for a way to fix this, please see the "advanced hook types" section).

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(" "). For the other arguments, see the "shared arguments

Regex Hook

@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.

Event Hook

@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.

Needs to be expanded

Sieve Hook

@hook.sieve(bot, input, func, type, args)

Allows you filter or cancel different actions.

To cancel a action, return None.

Needs to be expanded

Secondary Hook: Singlethread

@hook.singlethread

This is a secondary hook, used to tell a hook to run on its own thread. (not that the existing database connection will be unusable).

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

shared 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)

usage:

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)
<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)

advanced hook types:

For hooks that should only work for admins, add adminonly=True to the hook (not the function). 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)

(this is only relevant on command hooks)

Getting Help

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

Clone this wiki locally