setting up threading and two IRC sockets setting up watcher to report recent changes to a given list of channels on the main srver code cleanuptags/v0.1
@@ -1,69 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
## Imports | |||
import socket, re, time | |||
from config.irc_config import * | |||
from config.secure_config import * | |||
from irc import triggers | |||
from irc.actions import * | |||
from irc.data import * | |||
def main(): | |||
read_buffer = str() | |||
while 1: | |||
try: | |||
read_buffer = read_buffer + actions.get() | |||
except RuntimeError: # socket broke | |||
print "socket has broken, sleeping for a minute and restarting..." | |||
time.sleep(60) # sleep for sixty seconds | |||
return # then exit our loop and restart the bot | |||
lines = read_buffer.split("\n") | |||
read_buffer = lines.pop() | |||
for line in lines: | |||
line = line.strip().split() | |||
data = Data() | |||
if line[1] == "JOIN": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.chan = line[2][1:] | |||
triggers.check(actions, data, "join") # check if there's anything we can respond to, and if so, respond | |||
if line[1] == "PRIVMSG": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.msg = ' '.join(line[3:])[1:] | |||
data.chan = line[2] | |||
if data.chan == NICK: # this is a privmsg to us, so set 'chan' as the nick of the sender | |||
data.chan = data.nick | |||
triggers.check(actions, data, "msg_private") # only respond if it's a private message | |||
else: | |||
triggers.check(actions, data, "msg_public") # only respond if it's a public (channel) message | |||
triggers.check(actions, data, "msg") # check for general messages | |||
if data.msg == "!restart": # hardcode the !restart command (we can't return from within actions.py) | |||
if data.host in ADMINS: | |||
return True | |||
if line[0] == "PING": # If we are pinged, pong back to the server | |||
actions.send("PONG %s" % line[1]) | |||
if line[1] == "376": | |||
if NS_AUTH: # if we're supposed to auth to nickserv, do that | |||
actions.say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||
for chan in CHANS: # join all of our startup channels | |||
actions.join(chan) | |||
if __name__ == "__main__": | |||
sock = socket.socket() | |||
sock.connect((HOST, PORT)) | |||
actions = Actions(sock) | |||
actions.send("NICK %s" % NICK) | |||
actions.send("USER %s %s bla :%s" % (IDENT, HOST, REALNAME)) | |||
main() |
@@ -3,23 +3,24 @@ | |||
# EarwigBot Configuration File | |||
# This file contains information that the bot uses to connect to IRC. | |||
# our server's hostname | |||
# our main (front-end) server's hostname and port | |||
HOST = "irc.freenode.net" | |||
# our server's port | |||
PORT = 6667 | |||
# our nick | |||
NICK = "EarwigBot" | |||
# our watcher server's hostname, port, and RC channel | |||
WATCHER_HOST = "irc.wikimedia.org" | |||
WATCHER_PORT = 6667 | |||
WATCHER_CHAN = "#en.wikipedia" | |||
# our ident | |||
# our nick, ident, and real name, used on both servers | |||
NICK = "EarwigBot" | |||
IDENT = "earwigbot" | |||
# our real name | |||
REALNAME = "[[w:en:User:EarwigBot]]" | |||
# channel to join on startup | |||
# channels to join on main server's startup | |||
CHANS = ["##earwigbot", "##earwig", "#wikipedia-en-afc"] | |||
AFC_CHANS = ["#wikipedia-en-afc"] # report recent AFC changes | |||
BOT_CHANS = ["##earwigbot", "#wikipedia-en-afc"] # report edits containing "!earwigbot" | |||
# hostnames of users who can update/restart the bot with !update | |||
# hardcoded hostnames of users who can use !restart and !git | |||
ADMINS = ["wikipedia/The-Earwig"] |
@@ -0,0 +1,50 @@ | |||
# -*- coding: utf-8 -*- | |||
## EarwigBot's Core | |||
## Basically, this creates threads for our IRC watcher component and Wikipedia component, and then runs the main IRC bot on the main thread. | |||
## The IRC bot component of EarwigBot has two parts: a front-end and a watcher. | |||
## The front-end runs on a normal IRC server and expects users to interact with it/give it commands. | |||
## The watcher runs on a wiki recent-changes server and listens for edits. Users cannot interact with this part of the bot. | |||
import threading | |||
import time | |||
import traceback | |||
import sys | |||
import os | |||
parent_dir = os.path.split(sys.path[0])[0] | |||
sys.path.append(parent_dir) # make sure we look in the parent directory for modules | |||
from irc import frontend, watcher | |||
f_conn = None | |||
w_conn = None | |||
def irc_watcher(f_conn): | |||
global w_conn | |||
while 1: # restart the watcher component if (just) it breaks | |||
w_conn = watcher.get_connection() | |||
try: | |||
watcher.main(w_conn, f_conn) | |||
except: | |||
traceback.print_exc() | |||
time.sleep(5) # sleep a bit before restarting watcher | |||
print "restarting watcher component..." | |||
def run(): | |||
global f_conn | |||
f_conn = frontend.get_connection() | |||
t_watcher = threading.Thread(target=irc_watcher, args=(f_conn,)) | |||
t_watcher.daemon = True | |||
t_watcher.start() | |||
frontend.main(f_conn) | |||
if __name__ == "__main__": | |||
try: | |||
run() | |||
finally: | |||
f_conn.close() | |||
w_conn.close() |
@@ -0,0 +1,15 @@ | |||
# -*- coding: utf-8 -*- | |||
import time | |||
from subprocess import * | |||
try: | |||
from config import irc_config, secure_config | |||
except ImportError: | |||
print """Missing a config file! Make sure you have configured the bot. All *.py.default files in config/ | |||
should have their .default extension removed, and the info inside should be corrected.""" | |||
exit() | |||
while 1: | |||
call(['python', 'core/main.py']) | |||
time.sleep(5) # sleep for five seconds between bot runs |
@@ -1,40 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
# Actions/commands to interface with IRC. | |||
class Actions: | |||
def __init__(self, sock): | |||
"""actions/commands to interface with IRC""" | |||
self.sock = sock | |||
def get(self, size = 4096): | |||
"""receive (get) data from the server""" | |||
data = self.sock.recv(4096) | |||
if not data: | |||
raise RuntimeError("socket is dead") | |||
return data | |||
def send(self, msg): | |||
"""send data to the server""" | |||
self.sock.send(msg + "\r\n") | |||
print " %s" % msg | |||
def say(self, target, msg): | |||
"""send a message""" | |||
self.send("PRIVMSG %s :%s" % (target, msg)) | |||
def reply(self, target, nick, msg): | |||
"""send a message as a reply""" | |||
self.say(target, "%s%s%s: %s" % (chr(2), nick, chr(0x0f), msg)) | |||
def action(self, target, msg): | |||
"""send a message as an action""" | |||
self.say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||
def notice(self, target, msg): | |||
"""send a notice""" | |||
self.send("NOTICE %s :%s" % (target, msg)) | |||
def join(self, chan): | |||
"""join a channel""" | |||
self.send("JOIN %s" % chan) |
@@ -5,18 +5,18 @@ | |||
import shlex, subprocess, re | |||
from config.irc_config import * | |||
actions, data = None, None | |||
connection, data = None, None | |||
def call(a, d): | |||
global actions, data | |||
actions, data = a, d | |||
def call(c, d): | |||
global connection, data | |||
connection, data = c, d | |||
if data.host not in ADMINS: | |||
actions.reply(data.chan, data.nick, "you must be a bot admin to use this command.") | |||
connection.reply(data.chan, data.nick, "you must be a bot admin to use this command.") | |||
return | |||
if not data.args: | |||
actions.reply(data.chan, data.nick, "no arguments provided.") | |||
connection.reply(data.chan, data.nick, "no arguments provided.") | |||
return | |||
if data.args[0] == "help": | |||
@@ -41,7 +41,7 @@ def call(a, d): | |||
do_status() | |||
else: # they asked us to do something we don't know | |||
actions.reply(data.chan, data.nick, "unknown argument: \x0303%s\x0301." % data.args[0]) | |||
connection.reply(data.chan, data.nick, "unknown argument: \x0303%s\x0301." % data.args[0]) | |||
def exec_shell(command): | |||
"""execute a shell command and get the output""" | |||
@@ -68,14 +68,14 @@ def do_help(): | |||
help += "\x0303%s\x0301 (%s), " % (key, help_dict[key]) | |||
help = help[:-2] # trim last comma | |||
actions.reply(data.chan, data.nick, "sub-commands are: %s." % help) | |||
connection.reply(data.chan, data.nick, "sub-commands are: %s." % help) | |||
def do_branch(): | |||
"""get our current branch""" | |||
branch = exec_shell("git name-rev --name-only HEAD") | |||
branch = branch[:-1] # strip newline | |||
actions.reply(data.chan, data.nick, "currently on branch \x0302%s\x0301." % branch) | |||
connection.reply(data.chan, data.nick, "currently on branch \x0302%s\x0301." % branch) | |||
def do_branches(): | |||
"""get list of branches""" | |||
@@ -87,66 +87,66 @@ def do_branches(): | |||
branches = branches.replace('\n ', ', ') | |||
branches = branches.strip() | |||
actions.reply(data.chan, data.nick, "branches: \x0302%s\x0301." % branches) | |||
connection.reply(data.chan, data.nick, "branches: \x0302%s\x0301." % branches) | |||
def do_checkout(): | |||
"""switch branches""" | |||
try: | |||
branch = data.args[1] | |||
except IndexError: # no branch name provided | |||
actions.reply(data.chan, data.nick, "switch to which branch?") | |||
connection.reply(data.chan, data.nick, "switch to which branch?") | |||
return | |||
try: | |||
result = exec_shell("git checkout %s" % branch) | |||
if "Already on" in result: | |||
actions.reply(data.chan, data.nick, "already on \x0302%s\x0301!" % branch) | |||
connection.reply(data.chan, data.nick, "already on \x0302%s\x0301!" % branch) | |||
else: | |||
actions.reply(data.chan, data.nick, "switched to branch \x0302%s\x0301." % branch) | |||
connection.reply(data.chan, data.nick, "switched to branch \x0302%s\x0301." % branch) | |||
except subprocess.CalledProcessError: # git couldn't switch branches | |||
actions.reply(data.chan, data.nick, "branch \x0302%s\x0301 doesn't exist!" % branch) | |||
connection.reply(data.chan, data.nick, "branch \x0302%s\x0301 doesn't exist!" % branch) | |||
def do_delete(): | |||
"""delete a branch, while making sure that we are not on it""" | |||
try: | |||
delete_branch = data.args[1] | |||
except IndexError: # no branch name provided | |||
actions.reply(data.chan, data.nick, "delete which branch?") | |||
connection.reply(data.chan, data.nick, "delete which branch?") | |||
return | |||
current_branch = exec_shell("git name-rev --name-only HEAD") | |||
current_branch = current_branch[:-1] # strip newline | |||
if current_branch == delete_branch: | |||
actions.reply(data.chan, data.nick, "you're currently on this branch; please checkout to a different branch before deleting.") | |||
connection.reply(data.chan, data.nick, "you're currently on this branch; please checkout to a different branch before deleting.") | |||
return | |||
try: | |||
exec_shell("git branch -d %s" % delete_branch) | |||
actions.reply(data.chan, data.nick, "branch \x0302%s\x0301 has been deleted locally." % delete_branch) | |||
connection.reply(data.chan, data.nick, "branch \x0302%s\x0301 has been deleted locally." % delete_branch) | |||
except subprocess.CalledProcessError: # git couldn't delete | |||
actions.reply(data.chan, data.nick, "branch \x0302%s\x0301 doesn't exist!" % delete_branch) | |||
connection.reply(data.chan, data.nick, "branch \x0302%s\x0301 doesn't exist!" % delete_branch) | |||
def do_pull(): | |||
"""pull from remote repository""" | |||
branch = exec_shell("git name-rev --name-only HEAD") | |||
branch = branch[:-1] # strip newline | |||
actions.reply(data.chan, data.nick, "pulling from remote (currently on \x0302%s\x0301)..." % branch) | |||
connection.reply(data.chan, data.nick, "pulling from remote (currently on \x0302%s\x0301)..." % branch) | |||
result = exec_shell("git pull") | |||
if "Already up-to-date." in result: | |||
actions.reply(data.chan, data.nick, "done; no new changes.") | |||
connection.reply(data.chan, data.nick, "done; no new changes.") | |||
else: | |||
changes = re.findall("\s*((.*?)\sfile(.*?)tions?\(-\))", result)[0][0] # find the changes | |||
actions.reply(data.chan, data.nick, "done; %s." % changes) | |||
connection.reply(data.chan, data.nick, "done; %s." % changes) | |||
def do_status(): | |||
"""check whether we have anything to pull""" | |||
actions.reply(data.chan, data.nick, "checking remote for updates...") | |||
connection.reply(data.chan, data.nick, "checking remote for updates...") | |||
result = exec_shell("git fetch --dry-run") | |||
if not result: | |||
actions.reply(data.chan, data.nick, "local copy is up-to-date with remote.") | |||
connection.reply(data.chan, data.nick, "local copy is up-to-date with remote.") | |||
else: | |||
actions.reply(data.chan, data.nick, "remote is ahead of local copy.") | |||
connection.reply(data.chan, data.nick, "remote is ahead of local copy.") |
@@ -2,11 +2,11 @@ | |||
"""Generates help information.""" | |||
actions, data = None, None | |||
connection, data = None, None | |||
def call(a, d): | |||
global actions, data | |||
actions, data = a, d | |||
def call(c, d): | |||
global connection, data | |||
connection, data = c, d | |||
if not data.args: | |||
do_general_help() | |||
@@ -15,7 +15,7 @@ def call(a, d): | |||
do_command_help() | |||
def do_general_help(): | |||
actions.reply(data.chan, data.nick, "I am a bot! You can get help for any command by typing '!help <command>'.") | |||
connection.reply(data.chan, data.nick, "I am a bot! You can get help for any command by typing '!help <command>'.") | |||
def do_command_help(): | |||
command = data.args[0] | |||
@@ -23,12 +23,12 @@ def do_command_help(): | |||
try: | |||
exec "from irc.commands import %s as this_command" % command | |||
except ImportError: | |||
actions.reply(data.chan, data.nick, "command \x0303%s\x0301 not found!" % command) | |||
connection.reply(data.chan, data.nick, "command \x0303%s\x0301 not found!" % command) | |||
return | |||
info = this_command.__doc__ | |||
if info: | |||
actions.reply(data.chan, data.nick, "info for command \x0303%s\x0301: \"%s\"" % (command, info)) | |||
connection.reply(data.chan, data.nick, "info for command \x0303%s\x0301: \"%s\"" % (command, info)) | |||
else: | |||
actions.reply(data.chan, data.nick, "sorry, no information for \x0303%s\x0301." % command) | |||
connection.reply(data.chan, data.nick, "sorry, no information for \x0303%s\x0301." % command) |
@@ -4,17 +4,17 @@ | |||
import random | |||
actions, data = None, None | |||
connection, data = None, None | |||
def call(a, d): | |||
global actions, data | |||
actions, data = a, d | |||
def call(c, d): | |||
global connection, data | |||
connection, data = c, d | |||
choices = ("say_hi()", "say_sup()") | |||
exec random.choice(choices) | |||
def say_hi(): | |||
actions.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||
connection.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||
def say_sup(): | |||
actions.say(data.chan, "'sup \x02%s\x0F?" % data.nick) | |||
connection.say(data.chan, "'sup \x02%s\x0F?" % data.nick) |
@@ -0,0 +1,67 @@ | |||
# -*- coding: utf-8 -*- | |||
# A class to interface with IRC. | |||
import socket | |||
import threading | |||
class Connection: | |||
def __init__(self, host, port, nick, ident, realname): | |||
"""a class to interface with IRC""" | |||
self.host = host | |||
self.port = port | |||
self.nick = nick | |||
self.ident = ident | |||
self.realname = realname | |||
def connect(self): | |||
"""connect to IRC""" | |||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
self.sock.connect((self.host, self.port)) | |||
self.send("NICK %s" % self.nick) | |||
self.send("USER %s %s * :%s" % (self.ident, self.host, self.realname)) | |||
def close(self): | |||
"""close our connection with IRC""" | |||
try: | |||
self.sock.shutdown(socket.SHUT_RDWR) # shut down connection first | |||
except socket.error: | |||
pass # ignore if the socket is already down | |||
self.sock.close() | |||
def get(self, size=4096): | |||
"""receive (get) data from the server""" | |||
data = self.sock.recv(4096) | |||
if not data: # socket giving us no data, so it is dead/broken | |||
raise RuntimeError("socket is dead") | |||
return data | |||
def send(self, msg): | |||
"""send data to the server""" | |||
lock = threading.Lock() | |||
lock.acquire() # ensure that we only send one message at a time (blocking) | |||
try: | |||
self.sock.sendall(msg + "\r\n") | |||
print " %s" % msg | |||
finally: | |||
lock.release() | |||
def say(self, target, msg): | |||
"""send a message""" | |||
self.send("PRIVMSG %s :%s" % (target, msg)) | |||
def reply(self, target, nick, msg): | |||
"""send a message as a reply""" | |||
self.say(target, "%s%s%s: %s" % (chr(2), nick, chr(0x0f), msg)) | |||
def action(self, target, msg): | |||
"""send a message as an action""" | |||
self.say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||
def notice(self, target, msg): | |||
"""send a notice""" | |||
self.send("NOTICE %s :%s" % (target, msg)) | |||
def join(self, chan): | |||
"""join a channel""" | |||
self.send("JOIN %s" % chan) |
@@ -22,7 +22,4 @@ class Data: | |||
except IndexError: | |||
self.command = None | |||
try: | |||
self.args = args[1:] # the command arguments | |||
except IndexError: | |||
self.args = None | |||
self.args = args[1:] # the command arguments |
@@ -0,0 +1,66 @@ | |||
# -*- coding: utf-8 -*- | |||
## Imports | |||
import re | |||
from config.irc_config import * | |||
from config.secure_config import * | |||
from irc import triggers | |||
from irc.connection import Connection | |||
from irc.data import Data | |||
def get_connection(): | |||
connection = Connection(HOST, PORT, NICK, IDENT, REALNAME) | |||
return connection | |||
def main(connection): | |||
connection.connect() | |||
read_buffer = str() | |||
while 1: | |||
try: | |||
read_buffer = read_buffer + connection.get() | |||
except RuntimeError: # socket broke | |||
print "socket has broken on front-end; restarting bot..." | |||
return | |||
lines = read_buffer.split("\n") | |||
read_buffer = lines.pop() | |||
for line in lines: | |||
line = line.strip().split() | |||
data = Data() | |||
if line[1] == "JOIN": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.chan = line[2][1:] | |||
triggers.check(connection, data, "join") # check if there's anything we can respond to, and if so, respond | |||
if line[1] == "PRIVMSG": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.msg = ' '.join(line[3:])[1:] | |||
data.chan = line[2] | |||
if data.chan == NICK: # this is a privmsg to us, so set 'chan' as the nick of the sender | |||
data.chan = data.nick | |||
triggers.check(connection, data, "msg_private") # only respond if it's a private message | |||
else: | |||
triggers.check(connection, data, "msg_public") # only respond if it's a public (channel) message | |||
triggers.check(connection, data, "msg") # check for general messages | |||
if data.msg.startswith("!restart"): # hardcode the !restart command (we can't restart from within an ordinary command) | |||
if data.host in ADMINS: | |||
print "restarting bot per admin request..." | |||
return | |||
if line[0] == "PING": # If we are pinged, pong back to the server | |||
connection.send("PONG %s" % line[1]) | |||
if line[1] == "376": | |||
if NS_AUTH: # if we're supposed to auth to nickserv, do that | |||
connection.say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||
for chan in CHANS: # join all of our startup channels | |||
connection.join(chan) |
@@ -0,0 +1,33 @@ | |||
# -*- coding: utf-8 -*- | |||
# A class to store data on an individual event received from our IRC watcher. | |||
import re | |||
class RC: | |||
def __init__(self, msg): | |||
"""store data on an individual event received from our IRC watcher""" | |||
self.msg = msg | |||
def parse(self): | |||
"""parse recent changes log into some variables""" | |||
msg = self.msg | |||
msg = re.sub("\x03([0-9]{1,2}(,[0-9]{1,2})?)?", "", msg) # strip IRC color codes; we don't want/need 'em | |||
msg = msg.strip() | |||
self.msg = msg | |||
# page name of the modified page | |||
# 'M' for minor edit, 'B' for bot edit, 'create' for a user creation log entry... | |||
try: | |||
page, flags, url, user, comment = re.findall("\A\[\[(.*?)\]\]\s(.*?)\s(http://.*?)\s\*\s(.*?)\s\*\s(.*?)\Z", msg)[0] | |||
except IndexError: # we're probably missing the http:// part, because it's a log entry, which lacks a url | |||
page, flags, user, comment = re.findall("\A\[\[(.*?)\]\]\s(.*?)\s\*\s(.*?)\s\*\s(.*?)\Z", msg)[0] | |||
url = "http://en.wikipedia.org/wiki/%s" % page | |||
flags = flags.strip() # flag tends to have a extraneous whitespace character at the end when it's a log entry | |||
self.page, self.flags, self.url, self.user, self.comment = page, flags, url, user, comment | |||
def pretty(self): | |||
"""make a nice, colorful message from self.msg to send to the front-end""" | |||
pretty = self.msg | |||
return pretty |
@@ -4,7 +4,7 @@ | |||
from irc.commands import test, help, git | |||
def check(actions, data, hook): | |||
def check(connection, data, hook): | |||
data.parse_args() # parse command arguments into data.command and data.args | |||
if hook == "join": | |||
@@ -18,10 +18,10 @@ def check(actions, data, hook): | |||
if hook == "msg": | |||
if data.command == "!test": | |||
test.call(actions, data) | |||
test.call(connection, data) | |||
elif data.command == "!help": | |||
help.call(actions, data) | |||
help.call(connection, data) | |||
elif data.command == "!git": | |||
git.call(actions, data) | |||
git.call(connection, data) |
@@ -0,0 +1,71 @@ | |||
# -*- coding: utf-8 -*- | |||
## Imports | |||
import re | |||
from config.irc_config import * | |||
from irc.connection import Connection | |||
from irc.rc import RC | |||
global frontend_conn | |||
def get_connection(): | |||
connection = Connection(WATCHER_HOST, WATCHER_PORT, NICK, IDENT, REALNAME) | |||
return connection | |||
def main(connection, f_conn): | |||
global frontend_conn | |||
frontend_conn = f_conn | |||
connection.connect() | |||
read_buffer = str() | |||
while 1: | |||
try: | |||
read_buffer = read_buffer + connection.get() | |||
except RuntimeError: # socket broke | |||
print "socket has broken on watcher, restarting component..." | |||
return | |||
lines = read_buffer.split("\n") | |||
read_buffer = lines.pop() | |||
for line in lines: | |||
line = line.strip().split() | |||
if line[1] == "PRIVMSG": | |||
chan = line[2] | |||
if chan != WATCHER_CHAN: # if we're getting a msg from another channel, ignore it | |||
continue | |||
msg = ' '.join(line[3:])[1:] | |||
rc = RC(msg) # create a new RC object to store this change's data | |||
rc.parse() | |||
check(rc) | |||
if line[0] == "PING": # If we are pinged, pong back to the server | |||
connection.send("PONG %s" % line[1]) | |||
if line[1] == "376": # Join the recent changes channel when we've finished starting up | |||
connection.join(WATCHER_CHAN) | |||
def report(msg, chans): | |||
"""send a message to a list of report channels on our front-end server""" | |||
for chan in chans: | |||
frontend_conn.say(chan, msg) | |||
def check(rc): | |||
"""check to see if """ | |||
page_name = rc.page.lower() | |||
pretty_msg = rc.pretty() | |||
if "!earwigbot" in rc.msg.lower(): | |||
report(pretty_msg, chans=BOT_CHANS) | |||
if re.match("wikipedia( talk)?:(wikiproject )?articles for creation", page_name): | |||
report(pretty_msg, chans=AFC_CHANS) | |||
elif re.match("wikipedia( talk)?:files for upload", page_name): | |||
report(pretty_msg, chans=AFC_CHANS) | |||
elif page_name.startswith("template:afc submission"): | |||
report(pretty_msg, chans=AFC_CHANS) | |||
if rc.flags == "delete" and re.match("deleted \"\[\[wikipedia( talk)?:(wikiproject )?articles for creation", rc.comment.lower()): | |||
report(pretty_msg, chans=AFC_CHANS) |
@@ -1,14 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
from subprocess import * | |||
try: | |||
from config.secure_config import * | |||
except ImportError: | |||
print "Can't find a secure_config file!" | |||
print "Make sure you have configured the bot by moving 'config/secure_config.py.default' to 'config/secure_config.py' and by filling out the information inside." | |||
exit() | |||
while 1: | |||
cmd = ['python', 'bot.py'] | |||
call(cmd) |