def handle_privmsg(sock, line, state_change, state_file, lines_since_write, lines_since_sort_chk): global gen_cmd #get some information (user, nick, host, etc.) success, info, line = get_token(line, ' ') info = info.lstrip(':') success, nick, info = get_token(info, '!') success, realname, info = get_token(info, '@') success, hostmask, info = get_token(info, ' ') success, privmsg_cmd, line = get_token(line, ' ') success, channel, line = get_token(line, ' ') if (line.startswith(':')): line = line[1:] #debug log_line('[' + channel + '] <' + nick + '> ' + line) #ignore blacklisted users, #but throw some output on the console so we know that's happening if nick in ignored_users: print('Warn: ignored line from ' + nick + ' because their nick is blacklisted (ignored)') return (lines_since_write, lines_since_sort_chk) #strip trailing whitespace because users expect that to not matter line = line.rstrip(' ').rstrip("\t") #and now because whitespace is gone it's possible to have a blank line #so ignore blank lines if (line == ''): return (lines_since_write, lines_since_sort_chk) #if they PM'd us, then PM 'em right back #that'll show 'em is_pm = False if (channel == bot_nick): is_pm = True channel = nick success, cmd, line_post_cmd = get_token(line, ' ') dbg_str = '' #at ente's request; allow users in "debug" channels to read the bot's mind # net_dbg=False net_dbg = True cmd_esc = '!' #support question/answer style markov chain-ing stuff if (cmd.startswith(bot_nick)): output, dbg_str = markov.gen_from_str(state_change, use_pg, db_login, irc_str_map(line_post_cmd), random.randint(0, 1) + 1, retries_left=3) #if it didn't have that word as a starting state, #then just go random (fall back functionality) if (output == ''): output, dbg_str = markov.generate(state_change, use_pg=use_pg, db_login=db_login, back_gen=False) #prevent generating commands directed towards other bots, #if configured to do that if (not gen_cmd): if (output.startswith('!')): output = '\\' + output dbg_str = '[dbg] generated from line \"' + line_post_cmd + '\"' + "\n" + dbg_str py3queueln(sock, 'PRIVMSG ' + channel + ' :' + output, 1) #because people often talk to the bot in complete phrases, #go ahead and include these lines in the learning set lines_since_write, lines_since_sort_chk = learn_from( line, state_change, state_file, lines_since_write, lines_since_sort_chk) dbg_output(sock, dbg_str) return (lines_since_write, lines_since_sort_chk) #if this was a command for the bot cmd_handled, cmd_dbg_str = handle_bot_cmd(sock, cmd_esc, cmd, line_post_cmd, channel, nick, is_pm, state_change, use_pg, db_login) if (cmd_handled): #then it's handled and we're done #debug if the command gave us a debug string dbg_str = cmd_dbg_str #if it wasn't a command, then add this to the markov chain state and update the file on disk else: #if this was a pm then let the user know how to get help if they want it if (is_pm): py3queueln( sock, 'PRIVMSG ' + channel + ' :learning... (use ' + cmd_esc + 'help to get help, or ' + cmd_esc + 'wut to generate text)', 3) lines_since_write, lines_since_sort_chk = learn_from( line, state_change, state_file, lines_since_write, lines_since_sort_chk) #if we're debugging over the network, then output to the debug channels if (net_dbg): dbg_output(sock, dbg_str) return (lines_since_write, lines_since_sort_chk)
def handle_privmsg(sock,line,state_change,state_file,lines_since_write,lines_since_sort_chk): global gen_cmd #get some information (user, nick, host, etc.) success,info,line=get_token(line,' ') info=info.lstrip(':') success,nick,info=get_token(info,'!') success,realname,info=get_token(info,'@') success,hostmask,info=get_token(info,' ') success,privmsg_cmd,line=get_token(line,' ') success,channel,line=get_token(line,' ') if(line.startswith(':')): line=line[1:] #debug log_line('['+channel+'] <'+nick+'> '+line) #ignore blacklisted users, #but throw some output on the console so we know that's happening if nick in ignored_users: print('Warn: ignored line from '+nick+' because their nick is blacklisted (ignored)') return (lines_since_write,lines_since_sort_chk) #strip trailing whitespace because users expect that to not matter line=line.rstrip(' ').rstrip("\t") #and now because whitespace is gone it's possible to have a blank line #so ignore blank lines if(line==''): return (lines_since_write,lines_since_sort_chk) #if they PM'd us, then PM 'em right back #that'll show 'em is_pm=False if(channel==bot_nick): is_pm=True channel=nick success,cmd,line_post_cmd=get_token(line,' ') dbg_str='' #at ente's request; allow users in "debug" channels to read the bot's mind # net_dbg=False net_dbg=True cmd_esc='!' #support question/answer style markov chain-ing stuff if(cmd.startswith(bot_nick)): output,dbg_str=markov.gen_from_str(state_change,use_pg,db_login,irc_str_map(line_post_cmd),random.randint(0,1)+1,retries_left=3) #if it didn't have that word as a starting state, #then just go random (fall back functionality) if(output==''): output,dbg_str=markov.generate(state_change,use_pg=use_pg,db_login=db_login,back_gen=False) #prevent generating commands directed towards other bots, #if configured to do that if(not gen_cmd): if(output.startswith('!')): output='\\'+output dbg_str='[dbg] generated from line \"'+line_post_cmd+'\"'+"\n"+dbg_str py3queueln(sock,'PRIVMSG '+channel+' :'+output,1) #because people often talk to the bot in complete phrases, #go ahead and include these lines in the learning set lines_since_write,lines_since_sort_chk=learn_from(line,state_change,state_file,lines_since_write,lines_since_sort_chk) dbg_output(sock,dbg_str) return (lines_since_write,lines_since_sort_chk) #if this was a command for the bot cmd_handled,cmd_dbg_str=handle_bot_cmd(sock,cmd_esc,cmd,line_post_cmd,channel,nick,is_pm,state_change,use_pg,db_login) if(cmd_handled): #then it's handled and we're done #debug if the command gave us a debug string dbg_str=cmd_dbg_str #if it wasn't a command, then add this to the markov chain state and update the file on disk else: #if this was a pm then let the user know how to get help if they want it if(is_pm): py3queueln(sock,'PRIVMSG '+channel+' :learning... (use '+cmd_esc+'help to get help, or '+cmd_esc+'wut to generate text)',3) lines_since_write,lines_since_sort_chk=learn_from(line,state_change,state_file,lines_since_write,lines_since_sort_chk) #if we're debugging over the network, then output to the debug channels if(net_dbg): dbg_output(sock,dbg_str) return (lines_since_write,lines_since_sort_chk)
def handle_bot_cmd(sock, cmd_esc, cmd, line_post_cmd, channel, nick, is_pm, state_change, use_pg, db_login): global gen_cmd global unit_conv_list handled = False dbg_str = '' #check if this was a bot command if ((cmd == (cmd_esc + 'wut')) or (cmd == cmd_esc)): output = '' if (line_post_cmd != ''): output, dbg_str = markov.gen_from_str(state_change, use_pg, db_login, irc_str_map(line_post_cmd), random.randint(0, 1) + 1, retries_left=3) if (output == ''): output, dbg_str = markov.generate(state_change, use_pg=use_pg, db_login=db_login, back_gen=False) #prevent generating commands directed towards other bots, #if configured to do that if (not gen_cmd): if (output.startswith('!')): output = '\\' + output py3queueln(sock, 'PRIVMSG ' + channel + ' :' + output, 1) dbg_str = '[dbg] generated from line \"' + line_post_cmd + '\"' + "\n" + dbg_str handled = True elif (cmd == (cmd_esc + 'help')): if (is_pm): py3queueln( sock, 'PRIVMSG ' + channel + ' :This is a simple markov chain bot', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'wut -> generate text based on markov chains', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'help -> displays this command list', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'shup [min nice lvl] -> clears low-priority messages from sending queue (authorized users can clear higher priority messages)', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'part -> parts current channel (you can invite to me get back)', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'calc <expression> -> simple calculator; supports +,-,*,/,and ^; uses rpn internally', 3) # py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'wiki <topic> -> [EXPERIMENTAL] grabs first paragraph from wikipedia',3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'source -> links the github url for this bot\'s source code', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'omdb <movie name> -> grabs movie information from the open movie database', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'splchk <word> [edit dist] -> checks given word against a dictionary and suggests fixes', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'dieroll [sides] -> generates random number in range [1,sides]', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'time [utc offset tz] -> tells current UTC time, or if a timezone is given, current time in that timezone', 3) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + cmd_esc + 'timecalc <%R> <tz1> <tz2> -> tells what the given time (%R == hours:minutes on a 24-hour clock) at the first utc-offset timezone will be at the second utc-offset timezone', 3) for conversion in unit_conv_list: help_str = 'PRIVMSG ' + channel + ' :' + cmd_esc + conversion.from_abbr + '->' + conversion.to_abbr + ' <value>' while (len(help_str) < len('PRIVMSG ' + channel + ' :' + cmd_esc + 'XXXXXXXXXXXXXXXXXXXXXXXXXX')): help_str += ' ' help_str += '-> converts ' + conversion.dimension + ' from ' + conversion.from_disp + ' to ' + conversion.to_disp py3queueln(sock, help_str, 3) else: py3queueln( sock, 'PRIVMSG ' + channel + ' :This is a simple markov chain bot; use ' + cmd_esc + 'wut or address me by name to generate text; PM !help for more detailed help', 3) handled = True #clear (low-priority) messages from the output queue elif ((cmd == (cmd_esc + 'shup')) or (cmd == (cmd_esc + 'shoo'))): #the minimum nice value to clear messages from the output queue nice_lvl = 4 try: nice_lvl = int(line_post_cmd.strip(' ')) except ValueError: nice_lvl = 4 #authorized users can suppress high-priority output if (nick in authed_users): nice_lvl = max(nice_lvl, 1) #unauthorized users can only suppress low-priority output else: nice_lvl = max(nice_lvl, 4) py3clearq(nice_lvl) py3queueln( sock, 'PRIVMSG ' + channel + ' :Info: outgoing message queue cleared of low-priority messages (nice_lvl=' + str(nice_lvl) + ')', 1) handled = True elif (cmd == (cmd_esc + 'part')): if (not is_pm): py3queueln( sock, 'PART ' + channel + ' :Goodbye for now (you can invite me back any time)', 1) else: py3queueln( sock, 'PRIVMSG ' + channel + ' :part from where, asshole? this is a PM!', 1) handled = True #conversions are their own function now elif (handle_conversion(sock, cmd_esc, cmd, line_post_cmd, channel)): handled = True elif (cmd == (cmd_esc + 'calc')): try: err_msgs, result = rpn.rpn_eval(rpn.rpn_translate(line_post_cmd)) if (len(result) == 1): py3queueln(sock, 'PRIVMSG ' + channel + ' :' + str(result[0]), 1) else: py3queueln( sock, 'PRIVMSG ' + channel + ' :Warn: An error occurred during evaluation; simplified RPN expression is ' + str(result), 1) for err_idx in range(0, len(err_msgs)): py3queueln( sock, 'PRIVMSG ' + channel + ' :Err #' + str(err_idx) + ': ' + str(err_msgs[err_idx]), 3) #TODO: figure out why divide-by-0 is triggering a ValueError here, it should be handled elsewhere except ValueError: py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: Could not parse expression (ValueError) (divide by zero?)', 1) except IndexError: py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: Could not parse expression (IndexError) (mismatched parens?)', 1) except: py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: Unhandled exception in rpn parsing; tell neutrak the command you used to get this and he\'ll look into it', 1) handled = True elif (cmd == (cmd_esc + 'wiki')): #disabled because we have another bot to do this now return (True, dbg_str) #TODO: handle more specific errors; this is super nasty but should keep the bot from crashing try: wiki_title = line_post_cmd.replace(' ', '_') wiki_url = 'https://en.wikipedia.org/wiki/' + wiki_title response = http_cat.get_page(wiki_url) response_type = response[0].split("\n")[0].rstrip("\r") #if we get a 301 moved and the page requested was lower case then #before giving up try it as upper-case if ((response_type.find('301 Moved') >= 0) and (line_post_cmd[0] == line_post_cmd[0].lower())): return handle_bot_cmd(sock, cmd_esc, cmd, (line_post_cmd[0].upper()) + (line_post_cmd[1:]), channel, nick, is_pm, state_change, use_pg, db_login) if (response_type.find('200 OK') < 0): py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: \"' + response_type + '\"', 1) else: wiki_text = response[1] if (wiki_text == ''): py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: wiki got null page text', 1) else: #get the first paragraph and throw out nested html tags wiki_text = http_cat.html_parse_first( wiki_text, '<p>', '</p>') max_p_len = 768 wiki_text = wiki_text[0:max_p_len] line_len = 300 while (wiki_text != ''): line_delimiter = '. ' prd_idx = wiki_text.find(line_delimiter) if (prd_idx >= 0): prd_idx += len(line_delimiter) py3queueln( sock, 'PRIVMSG ' + channel + ' :' + wiki_text[0:prd_idx], 1) wiki_text = wiki_text[prd_idx:] else: py3queueln( sock, 'PRIVMSG ' + channel + ' :' + wiki_text[0:line_len], 1) wiki_text = wiki_text[line_len:] py3queueln(sock, 'PRIVMSG ' + channel + ' :' + wiki_url, 1) #link the wiki page itself? except: py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: wiki failed to get page text', 1) handled = True elif (cmd == (cmd_esc + 'source')): py3queueln( sock, 'PRIVMSG ' + channel + ' :bot source code: ' + SOURCE_CODE_URL, 1) handled = True elif ((cmd == (cmd_esc + 'omdb')) or (cmd == (cmd_esc + 'imdb'))): handle_omdb(sock, cmd_esc, cmd, line_post_cmd, channel, is_pm) handled = True elif ((cmd == (cmd_esc + 'splchk')) or (cmd == (cmd_esc + 'spellcheck')) or (cmd == (cmd_esc + 'sp')) or (cmd == (cmd_esc + 'spell'))): handle_spellcheck(sock, cmd_esc, cmd, line_post_cmd, channel, is_pm) handled = True elif (cmd == (cmd_esc + 'dieroll')): sides = 6 if (line_post_cmd != ''): try: sides = int(line_post_cmd) except ValueError: py3queueln( sock, 'PRIVMSG ' + channel + ' :Warn: Invalid number of sides, assuming d-6', 1) sides = 6 if (sides < 1): py3queueln( sock, 'PRIVMSG ' + channel + ' :Warn: Number of sides less than 1, setting number of sides 1 (this will return 1)', 1) sides = 1 value = random.randint(1, sides) py3queueln( sock, 'PRIVMSG ' + channel + ' :Rolled a ' + str(value) + ' with a d' + str(sides), 1) handled = True elif (cmd == (cmd_esc + 'time')): tz = 0 if (line_post_cmd != ''): try: tz = float(line_post_cmd) except ValueError: py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: ' + line_post_cmd + ' is not a valid UTC-offset timezone; will give UTC time instead...', 1) if (abs(tz) > 24): py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: timezone offsets from utc cannot be outside the range [-24,24] because that makes no sense; giving UTC time...' ) tz = 0 current_time = time.asctime(time.gmtime(time.time() + (tz * 60 * 60))) py3queueln( sock, 'PRIVMSG ' + channel + ' :Current time is ' + current_time + ' (UTC ' + ('+' + str(tz) if tz >= 0 else str(tz)) + ')') handled = True elif (cmd == (cmd_esc + 'timecalc')): handle_timecalc(sock, cmd_esc, cmd, line_post_cmd, channel, is_pm) handled = True elif (cmd.startswith(cmd_esc)): try: #alternate conversion syntax #check if the "command" is a valid floating point number conv_arg = float(cmd[len(cmd_esc):]) #the line after the "command" is the command checked against the conversion list #some arguments here are a little weird because they're being transposed found_conversion = False for conversion in unit_conv_list: #we found the requested conversion, so do the thing and output the result #note that "X to Y" gets translated here as "X->Y" if (conversion.chk_cmd( cmd_esc, cmd_esc + line_post_cmd.replace(' to ', '->'))): conversion.output_conv(sock, channel, conv_arg) found_conversion = True #this was a valid number, but something went wrong during conversion if (not found_conversion): py3queueln( sock, 'PRIVMSG ' + channel + ' :Err: Conversion not found ' + line_post_cmd, 1) #in any case if we got a number don't handle this line any more handled = True #the "command" wasn't a valid floating point number, #so output an error for PM, or just do nothing in a channel except ValueError: if (is_pm): py3queueln( sock, 'PRIVMSG ' + channel + ' :Warn: Invalid command: \"' + cmd + '\"; see ' + cmd_esc + 'help for help', 1) #this prevents the bot from learning from unrecognized ! commands #(which are usually meant for another bot) # handled=True #this was added at the request of NuclearWaffle, in an attempt, and I'm quoting here #to "f**k with Proview" # elif((len(cmd)>1) and odd_quest(cmd)): # output,dbg_str=markov.generate(state_change,use_pg=use_pg,db_login=db_login,back_gen=False) # # #prevent generating commands directed towards other bots, # #if configured to do that # if(not gen_cmd): # if(output.startswith('!')): # output='\\'+output # # py3queueln(sock,'PRIVMSG '+channel+' :'+output,1) # handled=True return (handled, dbg_str)
def handle_bot_cmd(sock,cmd_esc,cmd,line_post_cmd,channel,nick,is_pm,state_change,use_pg,db_login): global gen_cmd global unit_conv_list handled=False dbg_str='' #check if this was a bot command if((cmd==(cmd_esc+'wut')) or (cmd==cmd_esc)): output='' if(line_post_cmd!=''): output,dbg_str=markov.gen_from_str(state_change,use_pg,db_login,irc_str_map(line_post_cmd),random.randint(0,1)+1,retries_left=3) if(output==''): output,dbg_str=markov.generate(state_change,use_pg=use_pg,db_login=db_login,back_gen=False) #prevent generating commands directed towards other bots, #if configured to do that if(not gen_cmd): if(output.startswith('!')): output='\\'+output py3queueln(sock,'PRIVMSG '+channel+' :'+output,1) dbg_str='[dbg] generated from line \"'+line_post_cmd+'\"'+"\n"+dbg_str handled=True elif(cmd==(cmd_esc+'help')): if(is_pm): py3queueln(sock,'PRIVMSG '+channel+' :This is a simple markov chain bot',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'wut -> generate text based on markov chains',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'help -> displays this command list',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'shup [min nice lvl] -> clears low-priority messages from sending queue (authorized users can clear higher priority messages)',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'part -> parts current channel (you can invite to me get back)',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'calc <expression> -> simple calculator; supports +,-,*,/,and ^; uses rpn internally',3) # py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'wiki <topic> -> [EXPERIMENTAL] grabs first paragraph from wikipedia',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'source -> links the github url for this bot\'s source code',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'omdb <movie name> -> grabs movie information from the open movie database',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'splchk <word> [edit dist] -> checks given word against a dictionary and suggests fixes',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'dieroll [sides] -> generates random number in range [1,sides]',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'time [utc offset tz] -> tells current UTC time, or if a timezone is given, current time in that timezone',3) py3queueln(sock,'PRIVMSG '+channel+' :'+cmd_esc+'timecalc <%R> <tz1> <tz2> -> tells what the given time (%R == hours:minutes on a 24-hour clock) at the first utc-offset timezone will be at the second utc-offset timezone',3) for conversion in unit_conv_list: help_str='PRIVMSG '+channel+' :'+cmd_esc+conversion.from_abbr+'->'+conversion.to_abbr+' <value>' while(len(help_str)<len('PRIVMSG '+channel+' :'+cmd_esc+'XXXXXXXXXXXXXXXXXXXXXXXXXX')): help_str+=' ' help_str+='-> converts '+conversion.dimension+' from '+conversion.from_disp+' to '+conversion.to_disp py3queueln(sock,help_str,3) else: py3queueln(sock,'PRIVMSG '+channel+' :This is a simple markov chain bot; use '+cmd_esc+'wut or address me by name to generate text; PM !help for more detailed help',3) handled=True #clear (low-priority) messages from the output queue elif((cmd==(cmd_esc+'shup')) or (cmd==(cmd_esc+'shoo'))): #the minimum nice value to clear messages from the output queue nice_lvl=4 try: nice_lvl=int(line_post_cmd.strip(' ')) except ValueError: nice_lvl=4 #authorized users can suppress high-priority output if(nick in authed_users): nice_lvl=max(nice_lvl,1) #unauthorized users can only suppress low-priority output else: nice_lvl=max(nice_lvl,4) py3clearq(nice_lvl) py3queueln(sock,'PRIVMSG '+channel+' :Info: outgoing message queue cleared of low-priority messages (nice_lvl='+str(nice_lvl)+')',1) handled=True elif(cmd==(cmd_esc+'part')): if(not is_pm): py3queueln(sock,'PART '+channel+' :Goodbye for now (you can invite me back any time)',1) else: py3queueln(sock,'PRIVMSG '+channel+' :part from where, asshole? this is a PM!',1) handled=True #conversions are their own function now elif(handle_conversion(sock,cmd_esc,cmd,line_post_cmd,channel)): handled=True elif(cmd==(cmd_esc+'calc')): try: err_msgs,result=rpn.rpn_eval(rpn.rpn_translate(line_post_cmd)) if(len(result)==1): py3queueln(sock,'PRIVMSG '+channel+' :'+str(result[0]),1) else: py3queueln(sock,'PRIVMSG '+channel+' :Warn: An error occurred during evaluation; simplified RPN expression is '+str(result),1) for err_idx in range(0,len(err_msgs)): py3queueln(sock,'PRIVMSG '+channel+' :Err #'+str(err_idx)+': '+str(err_msgs[err_idx]),3) #TODO: figure out why divide-by-0 is triggering a ValueError here, it should be handled elsewhere except ValueError: py3queueln(sock,'PRIVMSG '+channel+' :Err: Could not parse expression (ValueError) (divide by zero?)',1) except IndexError: py3queueln(sock,'PRIVMSG '+channel+' :Err: Could not parse expression (IndexError) (mismatched parens?)',1) except: py3queueln(sock,'PRIVMSG '+channel+' :Err: Unhandled exception in rpn parsing; tell neutrak the command you used to get this and he\'ll look into it',1) handled=True elif(cmd==(cmd_esc+'wiki')): #disabled because we have another bot to do this now return (True,dbg_str) #TODO: handle more specific errors; this is super nasty but should keep the bot from crashing try: wiki_title=line_post_cmd.replace(' ','_') wiki_url='https://en.wikipedia.org/wiki/'+wiki_title response=http_cat.get_page(wiki_url) response_type=response[0].split("\n")[0].rstrip("\r") #if we get a 301 moved and the page requested was lower case then #before giving up try it as upper-case if((response_type.find('301 Moved')>=0) and (line_post_cmd[0]==line_post_cmd[0].lower())): return handle_bot_cmd(sock,cmd_esc, cmd, (line_post_cmd[0].upper())+(line_post_cmd[1:]), channel, nick,is_pm,state_change,use_pg,db_login) if(response_type.find('200 OK')<0): py3queueln(sock,'PRIVMSG '+channel+' :Err: \"'+response_type+'\"',1) else: wiki_text=response[1] if(wiki_text==''): py3queueln(sock,'PRIVMSG '+channel+' :Err: wiki got null page text',1) else: #get the first paragraph and throw out nested html tags wiki_text=http_cat.html_parse_first(wiki_text,'<p>','</p>') max_p_len=768 wiki_text=wiki_text[0:max_p_len] line_len=300 while(wiki_text!=''): line_delimiter='. ' prd_idx=wiki_text.find(line_delimiter) if(prd_idx>=0): prd_idx+=len(line_delimiter) py3queueln(sock,'PRIVMSG '+channel+' :'+wiki_text[0:prd_idx],1) wiki_text=wiki_text[prd_idx:] else: py3queueln(sock,'PRIVMSG '+channel+' :'+wiki_text[0:line_len],1) wiki_text=wiki_text[line_len:] py3queueln(sock,'PRIVMSG '+channel+' :'+wiki_url,1) #link the wiki page itself? except: py3queueln(sock,'PRIVMSG '+channel+' :Err: wiki failed to get page text',1) handled=True elif(cmd==(cmd_esc+'source')): py3queueln(sock,'PRIVMSG '+channel+' :bot source code: '+SOURCE_CODE_URL,1) handled=True elif((cmd==(cmd_esc+'omdb')) or (cmd==(cmd_esc+'imdb'))): handle_omdb(sock,cmd_esc,cmd,line_post_cmd,channel,is_pm) handled=True elif((cmd==(cmd_esc+'splchk')) or (cmd==(cmd_esc+'spellcheck')) or (cmd==(cmd_esc+'sp')) or (cmd==(cmd_esc+'spell'))): handle_spellcheck(sock,cmd_esc,cmd,line_post_cmd,channel,is_pm) handled=True elif(cmd==(cmd_esc+'dieroll')): sides=6 if(line_post_cmd!=''): try: sides=int(line_post_cmd) except ValueError: py3queueln(sock,'PRIVMSG '+channel+' :Warn: Invalid number of sides, assuming d-6',1) sides=6 if(sides<1): py3queueln(sock,'PRIVMSG '+channel+' :Warn: Number of sides less than 1, setting number of sides 1 (this will return 1)',1) sides=1 value=random.randint(1,sides) py3queueln(sock,'PRIVMSG '+channel+' :Rolled a '+str(value)+' with a d'+str(sides),1) handled=True elif(cmd==(cmd_esc+'time')): tz=0 if(line_post_cmd!=''): try: tz=float(line_post_cmd) except ValueError: py3queueln(sock,'PRIVMSG '+channel+' :Err: '+line_post_cmd+' is not a valid UTC-offset timezone; will give UTC time instead...',1) if(abs(tz)>24): py3queueln(sock,'PRIVMSG '+channel+' :Err: timezone offsets from utc cannot be outside the range [-24,24] because that makes no sense; giving UTC time...') tz=0 current_time=time.asctime(time.gmtime(time.time()+(tz*60*60))) py3queueln(sock,'PRIVMSG '+channel+' :Current time is '+current_time+' (UTC '+('+'+str(tz) if tz>=0 else str(tz))+')') handled=True elif(cmd==(cmd_esc+'timecalc')): handle_timecalc(sock,cmd_esc,cmd,line_post_cmd,channel,is_pm) handled=True elif(cmd.startswith(cmd_esc)): try: #alternate conversion syntax #check if the "command" is a valid floating point number conv_arg=float(cmd[len(cmd_esc):]) #the line after the "command" is the command checked against the conversion list #some arguments here are a little weird because they're being transposed found_conversion=False for conversion in unit_conv_list: #we found the requested conversion, so do the thing and output the result #note that "X to Y" gets translated here as "X->Y" if(conversion.chk_cmd(cmd_esc,cmd_esc+line_post_cmd.replace(' to ','->'))): conversion.output_conv(sock,channel,conv_arg) found_conversion=True #this was a valid number, but something went wrong during conversion if(not found_conversion): py3queueln(sock,'PRIVMSG '+channel+' :Err: Conversion not found '+line_post_cmd,1) #in any case if we got a number don't handle this line any more handled=True #the "command" wasn't a valid floating point number, #so output an error for PM, or just do nothing in a channel except ValueError: if(is_pm): py3queueln(sock,'PRIVMSG '+channel+' :Warn: Invalid command: \"'+cmd+'\"; see '+cmd_esc+'help for help',1) #this prevents the bot from learning from unrecognized ! commands #(which are usually meant for another bot) # handled=True #this was added at the request of NuclearWaffle, in an attempt, and I'm quoting here #to "f**k with Proview" # elif((len(cmd)>1) and odd_quest(cmd)): # output,dbg_str=markov.generate(state_change,use_pg=use_pg,db_login=db_login,back_gen=False) # # #prevent generating commands directed towards other bots, # #if configured to do that # if(not gen_cmd): # if(output.startswith('!')): # output='\\'+output # # py3queueln(sock,'PRIVMSG '+channel+' :'+output,1) # handled=True return (handled,dbg_str)