Building an IRC bot in python

From Media Design: Networked & Lens-Based wiki
Jump to navigation Jump to search

Somewhat redundant to example given on the IRC page.

The irc module provides a number of useful hooks/classes for writing python IRC bots.

sudo pip install irc

Hello

Here's a simple "hello" bot which responds to all chat messages by replying "HELLO".

import irc.bot

class HelloBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.channel = channel

    def on_welcome(self, c, e):
        c.join(self.channel)

    def on_privmsg(self, c, e):
        pass

    def on_pubmsg(self, c, e):
        # e.target, e.source, e.arguments, e.type
        print (e.arguments)
        c.privmsg(self.channel, "HELLO")


if __name__ == "__main__":
    import argparse
    import sys

    ap = argparse.ArgumentParser("IRC Bot")
    ap.add_argument("--server", default="irc.freenode.net")
    ap.add_argument("--port", type=int, default=6667)
    ap.add_argument("--channel", default="#pzi")
    ap.add_argument("--nickname", default="hellobot")
    args=ap.parse_args()

    bot = HelloBot(args.channel, args.nickname, args.server, args.port)
    bot.start()

Reverse Bot

import irc.bot

class FileBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.channel = channel

    def on_welcome(self, c, e):
        c.join(self.channel)

    def on_privmsg(self, c, e):
        pass

    def on_pubmsg(self, c, e):
        # e.target, e.source, e.arguments, e.type
        print e.arguments
        msg = e.arguments[0]
        words = msg.split()
        words.reverse()
        msg = " ".join(words)
        c.privmsg(self.channel, msg)


if __name__ == "__main__":
    import sys
    if len(sys.argv) != 4:
        print "Usage: reversebot.py <server[:port]> <channel> <nickname>"
        sys.exit(1)
    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print "Error: Erroneous port."
            sys.exit(1)
    else:
        port = 6667
    channel = sys.argv[2]
    nickname = sys.argv[3]
    bot = FileBot(channel, nickname, server, port)
    bot.start()

PIPEBOT

from __future__ import print_function
import irc.bot
import sys, time
from thread import start_new_thread


def chunks(l, n):
    """ Yield successive n-sized chunks from l.
    """
    for i in xrange(0, len(l), n):
        yield l[i:i+n]

class Bot (irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, input, port=6667, idle=False):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.input = input
        self.channel = channel
        if idle:
            start_new_thread(self.idle, ())

    def on_welcome(self, c, e):
        c.join(self.channel)
        print ("join", file=sys.stderr)
        start_new_thread(self.receive, (c,))

    def idle(self):
        while True:
            tstr = time.strftime("%H:%M:%S", time.localtime())
            out = u"({0}) {1}: {2}".format(tstr, "_system", "idle")
            sys.stdout.write(out.encode("utf-8")+"\n")
            sys.stdout.flush()
            time.sleep(1)

    def receive (self, c): 
        if self.input == sys.stdin:
            # print ("reading from stdin", file=sys.stderr)
            _in = sys.stdin
        else:
            # print ("reading from {0}".format(self.input), file=sys.stderr)
            _in = open(self.input)

        while True:
            line = _in.readline()
            if line == '':
                break
            line = line.rstrip().decode("utf-8")
            if line:
                # print ("read line: {0}".format(line), file=sys.stderr)
                # CHUNK IT
                for chunk in chunks(line, 400):
                    c.privmsg(self.channel, chunk)
        
    def on_pubmsg(self, c, e):
        # e.target, e.source, e.arguments, e.type
        msg = e.arguments[0]
        tstr = time.strftime("%H:%M:%S", time.localtime())
        nick = e.source.split("!", 1)[0]
        out = u"({0}) {1}: {2}".format(tstr, nick, msg)
        sys.stdout.write(out.encode("utf-8")+"\n")
        sys.stdout.flush()
        # print ("pubmsg: {0}".format(msg), file=sys.stderr)
        
if __name__ == "__main__":
    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument('--server', default='irc.freenode.net', help='server hostname (default: localhost)')
    parser.add_argument('--port', default=6667, type=int, help='server port (default: 6667)')
    parser.add_argument('--channel', default='#botopera', help='channel to join (default: #botopera)')
    parser.add_argument('--nickname', default='pipebot', help='bot nickname (default: pipebot)')
    parser.add_argument('--input', default=sys.stdin, help='input')
    parser.add_argument('--idle', default=False, action="store_true", help='output idle messages')
    args = parser.parse_args()

    bot = Bot(args.channel, args.nickname, args.server, args.input, port=args.port, idle=args.idle)
    bot.start()