This is the basic layout of an IRC bot with the socket module. The docstrings specify each method. The end result is a bot that connects to the channel and is able to respond to basic commands
https://github.com/metulburr?page=1&q=bo...C%93&q=IRC
Below are some modifications examples you can add to do specific things. This was wrote a long time ago...so i dont remember to a T everything...but some magic numbers usually chop the string up to get the wanted part. You dont have to do it the same of course.
One thing to note that is not in this previous code is the fact that the IRC will either kick you for flooding a channel or flush your message. What i mean by this is your bot may get kicked by sending a string that is of 1000 characters or so. This is not normal...but could happen depending on what the bot needs to output. To avoid this you can just split your message up into segments. For example....
keep a log of what people say...
import socket class IRCBot: def __init__(self, **kwargs): self.settings = { 'host':"irc.freenode.net", 'port':6667, 'channel':"#robgraves", 'contact': ":", 'nick':"mybot", 'ident':'mybot', 'realname':'mybot' } self.add_kwargs(kwargs) self.sock = self.irc_conn() self.main_loop() def add_kwargs(self, kwargs): ''' add keyword args as class attributes. This allows you to change the settings based on dict arg, and not have to hard code it in. The settings keys become this class' attributes. And the value becomes the value for those attributes. AKA self.nick = "mybot" etc. IRCbot(**{nick:"mybot2"}) IRCbot(**{nick:"mybot3"}) ''' for kwarg in kwargs: if kwarg in self.settings: self.settings[kwarg] = kwargs[kwarg] else: raise AttributeError("{} has no keyword: {}".format(self.__class__.__name__, kwarg)) self.__dict__.update(self.settings) def irc_conn(self): ''' connect to server/port channel, send nick/user ''' sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('connecting to "{0}/{1}"'.format(self.host, self.port)) sock.connect((self.host, self.port)) print('sending NICK "{}"'.format(self.nick)) sock.send("NICK {0}\r\n".format(self.nick).encode()) sock.send("USER {0} {0} bla :{0}\r\n".format( self.ident,self.host, self.realname).encode()) print('joining {}'.format(self.channel)) sock.send(str.encode('JOIN '+self.channel+'\n')) return sock def main_loop(self): ''' The main loop to keep the program running and waiting for commands ''' while True: self.parse_data() self.ping_pong() self.check_command() def get_user(self, stringer): '''get username from data string''' start = stringer.find('~') end = stringer.find('@') user = stringer[start +1:end] return user def parse_data(self): ''' get server data and parse it based on each message/command in irc ''' data=self.sock.recv(1042) #recieve server messages data = data.decode('utf-8') #data decoded self.data = data.strip('\n\r') #data stripped try: self.operation = data.split()[1] #get operation ie. JOIN/QUIT/PART/etc. textlist = data.split()[3:] text = ' '.join(textlist) self.text = text[1:] #content of each message self.addrname = self.get_user(data) #get address name self.username = data[:data.find('!')][1:] #get username self.cmd = self.text.split()[0][1:] except IndexError: #startup data has different layout than normal pass def ping_pong(self): ''' The server pings and anything that does not pong back gets kicked ''' try: if self.data[:4] == 'PING': self.send_operation('PONG') except TypeError: #startup data pass def send_operation(self, operation=None, msg=None, username=None): ''' the specific string structure of sending an operation and private message to one user ''' if msg is None: #send ping pong operation self.sock.send('{0} {1}\r\n'.format(operation, self.channel).encode()) elif msg != None: #send private msg to one username self.sock.send('PRIVMSG {0} :{1}\r\n'.format(self.username,msg).encode()) def say(self, string): ''' send string to channel...the equivalent to print() in the IRC channel ''' self.sock.send('PRIVMSG {0} :{1}\r\n'.format(self.channel, string).encode()) def check_command(self): ''' check each and every message for a command ''' if self.text[:1] == self.contact: #respond to only contact code to not respond to all messages if self.cmd == "help": self.say("you called me?") elif self.cmd == "yo": self.say("Yo-Yo") bot = IRCBot()
Output:<metulburr> :
<metulburr> help
<metulburr> :help
<mybot> you called me?
<metulburr> :test
<metulburr> :yo
<mybot> Yo-Yo
And of course once you do this you can build on this to do whatever. Such as...https://github.com/metulburr?page=1&q=bo...C%93&q=IRC
Below are some modifications examples you can add to do specific things. This was wrote a long time ago...so i dont remember to a T everything...but some magic numbers usually chop the string up to get the wanted part. You dont have to do it the same of course.
One thing to note that is not in this previous code is the fact that the IRC will either kick you for flooding a channel or flush your message. What i mean by this is your bot may get kicked by sending a string that is of 1000 characters or so. This is not normal...but could happen depending on what the bot needs to output. To avoid this you can just split your message up into segments. For example....
if len(str(string)) > 500: #protect from kicked for flooding s1 = sep_space(string[:500]) self.sock.send('PRIVMSG {0} :{1}\r\n'.format(self.channel, s1).encode()) s2 = sep_space(string[len(s1):1000]) self.sock.send('PRIVMSG {0} :{1}\r\n'.format(self.channel, s2).encode()) else: self.sock.send('PRIVMSG {0} :{1}\r\n'.format(self.channel, string).encode())Testing for people join or leaving a channel:
def upon_leave(self): '''when someone leaves the channel''' if self.operation == 'QUIT' or self.operation == 'PART': pass
def upon_join(self): '''when someone joins the channel''' if self.operation == 'JOIN': passrejoin a channel when an op likes to have fun and kick your bot. Unless they banned your bot.
def rejoin(self): '''rejoin when kicked''' if self.operation == 'KICK': if (self.text.split()[-1][1:]) == self.nick: self.sock.send(str.encode('JOIN '+self.channel+'\n')) self.insult() else: self.sock.send(str.encode('JOIN '+self.channel+'\n'))And be we warned of using eval(). For example if you eval a message, a message could contain a line of python code instead...executing it. And who knows what that line of code is. :naughty:
keep a log of what people say...
if self.operation == 'PRIVMSG' or self.operation == 'ACTION': if self.text[0] == '\x01': action = self.text[1:-1].split()[1:] action = ' '.join(action) self.last_said[self.username] = '*{} {}'.format(self.username, action) else: self.last_said[self.username] = self.textkeep track of when people were last on...
def seen(self, name=None): '''display last seen person's time and statement''' try: a = self.last_seen[name] b = datetime.datetime.now().replace(microsecond=0) diff = str(b - a) diff = diff.split(':') diff = '{} hr {} min {} sec'.format(diff[0], diff[1], diff[2]) said = ''.join(name + '\'s last statement: ' + self.last_said[name]) self.say('{} was last seen {} ago: {}'.format( name, diff, said )) except KeyError: self.say('{} has had no activity since I have been on'.format(name))
Recommended Tutorials: