From 6452c1169c0b610485ba5d568872a00ed2a209f9 Mon Sep 17 00:00:00 2001 From: Ryan Hitchman Date: Fri, 7 May 2010 17:16:44 -0600 Subject: [PATCH] disable !command, enable fuzzy command matching, make help automatic, add disabled_command (for fuzzy command match disabling), misc bugs --- bot.py | 6 +++++- core/config.py | 20 +++++++++++--------- core/main.py | 30 ++++++++++++++++++++++++------ plugins/babel.py | 6 ------ plugins/bf.py | 3 --- plugins/bigassmessage.py | 3 --- plugins/choose.py | 3 --- plugins/dice.py | 4 +--- plugins/dictionary.py | 11 +++-------- plugins/dotnetpad.py | 6 ------ plugins/down.py | 3 --- plugins/drama.py | 4 +--- plugins/explain.py | 2 -- plugins/gcalc.py | 2 -- plugins/google.py | 6 +----- plugins/help.py | 2 +- plugins/mem.py | 2 +- plugins/mtg.py | 3 --- plugins/profile.py | 4 +--- plugins/pyexec.py | 7 ++----- plugins/quote.py | 2 -- plugins/religion.py | 6 ------ plugins/remember.py | 2 -- plugins/seen.py | 3 --- plugins/sieve.py | 16 +++++++++------- plugins/suggest.py | 4 +--- plugins/tag.py | 3 --- plugins/tell.py | 4 ++-- plugins/tf.py | 3 --- plugins/twitter.py | 3 --- plugins/util/hook.py | 2 +- plugins/validate.py | 7 +------ plugins/weather.py | 2 +- plugins/wikipedia.py | 3 --- plugins/wolframalpha.py | 5 +---- plugins/youtube.py | 2 -- 36 files changed, 67 insertions(+), 127 deletions(-) diff --git a/bot.py b/bot.py index 1a5a359..4d8681d 100755 --- a/bot.py +++ b/bot.py @@ -25,6 +25,10 @@ eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(), os.path.join('core', 'reload.py'), 'exec')) reload(init=True) +config() +if not hasattr(bot, 'config'): + exit() + print 'Connecting to IRC' bot.conns = {} @@ -39,7 +43,7 @@ try: bot.conns[name] = IRC(conf['server'], conf['nick'], conf=conf, port=conf.get('port', 6667), channels=conf['channels']) except Exception, e: - print 'ERROR: malformed config file', Exception, e + print 'ERROR: malformed config file', e sys.exit() bot.persist_dir = os.path.abspath('persist') diff --git a/core/config.py b/core/config.py index 6f87ed3..1a4456a 100644 --- a/core/config.py +++ b/core/config.py @@ -3,10 +3,6 @@ import json import os -def load(): - return - - def save(conf): json.dump(conf, open('config', 'w'), sort_keys=True, indent=2) @@ -22,14 +18,20 @@ if not os.path.exists('config'): "nick": "skybot", "channels": ["#test"] } - } + }, + "disabled_plugins": [], + "disabled_commands": [], + "acls": {} }''') + '\n') -bot.config = json.load(open('config')) -bot._config_mtime = os.stat('config').st_mtime - def config(): # reload config from file if file has changed if bot._config_mtime != os.stat('config').st_mtime: - bot.config = json.load(open('config')) + try: + bot.config = json.load(open('config')) + except ValueError, e: + print 'ERROR: malformed config!', e + + +bot._config_mtime = 0 diff --git a/core/main.py b/core/main.py index c0ede36..4ff39b3 100644 --- a/core/main.py +++ b/core/main.py @@ -105,18 +105,33 @@ class Handler(object): self.input_queue.put(value) -def dispatch(input, kind, func, args): +def dispatch(input, kind, func, args, autohelp=False): for sieve, in bot.plugs['sieve']: input = do_sieve(sieve, bot, input, func, kind, args) if input == None: return + if autohelp and args.get('autohelp', True) and not input.inp: + input.reply(func.__doc__) + return + if func._thread: bot.threads[func].put(input) else: thread.start_new_thread(run, (func, input)) +def match_command(command): + commands = list(bot.commands) + + # do some fuzzy matching + prefix = filter(lambda x: x.startswith(command), commands) + if len(prefix) == 1: + return prefix[0] + + return command + + def main(conn, out): inp = Input(conn, *out) @@ -127,9 +142,9 @@ def main(conn, out): if inp.command == 'PRIVMSG': # COMMANDS if inp.chan == inp.nick: # private message, no command prefix - prefix = r'^(?:[.!]?|' + prefix = r'^(?:[.]?|' else: - prefix = r'^(?:[.!]|' + prefix = r'^(?:[.]|' command_re = prefix + inp.conn.nick command_re += r'[:,]*\s+)(\w+)(?:$|\s+)(.*)' @@ -137,14 +152,17 @@ def main(conn, out): m = re.match(command_re, inp.lastparam) if m: - command = m.group(1).lower() + trigger = m.group(1).lower() + command = match_command(trigger) + if command in bot.commands: input = Input(conn, *out) + input.trigger = trigger input.inp_unstripped = m.group(2) - input.inp = m.group(2).strip() + input.inp = input.inp_unstripped.strip() func, args = bot.commands[command] - dispatch(input, "command", func, args) + dispatch(input, "command", func, args, autohelp=True) # REGEXES for func, args in bot.plugs['regex']: diff --git a/plugins/babel.py b/plugins/babel.py index fea2dcc..e4880f1 100644 --- a/plugins/babel.py +++ b/plugins/babel.py @@ -55,9 +55,6 @@ def babel_gen(inp): def babel(inp): ".babel -- translates through multiple languages" - if not inp: - return babel.__doc__ - try: return list(babel_gen(inp))[-1][2] except IOError, e: @@ -68,9 +65,6 @@ def babel(inp): def babelext(inp): ".babelext -- like .babel, but with more detailed output" - if not inp: - return babelext.__doc__ - try: babels = list(babel_gen(inp)) except IOError, e: diff --git a/plugins/bf.py b/plugins/bf.py index 620716d..9e7d66c 100644 --- a/plugins/bf.py +++ b/plugins/bf.py @@ -15,9 +15,6 @@ MAX_STEPS = 1000000 def bf(inp): ".bf -- executes brainfuck program """ - if not inp: - return bf.__doc__ - program = re.sub('[^][<>+-.,]', '', inp) # create a dict of brackets pairs, for speed later on diff --git a/plugins/bigassmessage.py b/plugins/bigassmessage.py index d4bc6b9..9db7f19 100644 --- a/plugins/bigassmessage.py +++ b/plugins/bigassmessage.py @@ -5,9 +5,6 @@ from util import hook, http def bam(inp): ".bam [basic|magic|pepsi|jprdy] -- creates a big ass message" - if not inp: - return bam.__doc__ - host = 'http://bigassmessage.com/' path = 'dsx_BAM/boe.php?' params = {'action': 'saveMsg', 'theStyle': 'basic', 'theMessage': inp} diff --git a/plugins/choose.py b/plugins/choose.py index 971397b..89d200b 100644 --- a/plugins/choose.py +++ b/plugins/choose.py @@ -8,9 +8,6 @@ from util import hook def choose(inp): ".choose , , ... -- makes a decision" - if not inp: - return choose.__doc__ - c = re.findall(r'([^,]+)', inp) if len(c) == 1: c = re.findall(r'(\S+)', inp) diff --git a/plugins/dice.py b/plugins/dice.py index 25c3f2c..0ed6c03 100644 --- a/plugins/dice.py +++ b/plugins/dice.py @@ -30,13 +30,11 @@ def nrolls(count, n): (((n+1)*(2*n+1)/6.-(.5*(1+n))**2)*count)**.5)) -@hook.command @hook.command('roll') +@hook.command def dice(inp): ".dice -- simulates dicerolls, e.g. .dice 2d20-d5+4 roll 2 " \ "D20s, subtract 1D5, add 4" - if not inp: - return dice.__doc__ spec = whitespace_re.sub('', inp) if not valid_diceroll_re.match(spec): diff --git a/plugins/dictionary.py b/plugins/dictionary.py index c4e1d88..3049b08 100644 --- a/plugins/dictionary.py +++ b/plugins/dictionary.py @@ -7,9 +7,7 @@ from util import hook, http @hook.command def urban(inp): '''.u/.urban -- looks up on urbandictionary.com''' - if not inp: - return urban.__doc__ - + url = 'http://www.urbandictionary.com/define.php' page = http.get_html(url, term=inp) words = page.xpath("//td[@class='word']") @@ -28,13 +26,10 @@ def urban(inp): # define plugin by GhettoWizard & Scaevolus -@hook.command('dict') +@hook.command('dictionary') @hook.command def define(inp): - ".define/.dict -- fetches definition of " - - if not inp: - return define.__doc__ + ".define/.dictionary -- fetches definition of " url = 'http://ninjawords.com/' diff --git a/plugins/dotnetpad.py b/plugins/dotnetpad.py index edb22f3..e38b6af 100644 --- a/plugins/dotnetpad.py +++ b/plugins/dotnetpad.py @@ -47,9 +47,6 @@ def dotnetpad(lang, code, timeout=10): def fs(inp): ".fs -- post a F# code snippet to dotnetpad.net and print the results" - if not inp: - return fs.__doc__ - return dotnetpad('fsharp', inp) @@ -57,9 +54,6 @@ def fs(inp): def cs(snippet): ".cs -- post a C# code snippet to dotnetpad.net and print the results" - if not snippet: - return cs.__doc__ - file_template = ('using System; ' 'using System.Linq; ' 'using System.Collections.Generic; ' diff --git a/plugins/down.py b/plugins/down.py index c6848a0..120205f 100644 --- a/plugins/down.py +++ b/plugins/down.py @@ -7,9 +7,6 @@ from util import hook, http def down(inp): '''.down -- checks to see if the site is down''' - if not inp: - return down.__doc__ - if 'http://' not in inp: inp = 'http://' + inp diff --git a/plugins/drama.py b/plugins/drama.py index 8541930..681c3d8 100755 --- a/plugins/drama.py +++ b/plugins/drama.py @@ -12,9 +12,7 @@ ed_url = "http://encyclopediadramatica.com/" def drama(inp): '''.drama -- gets first paragraph of Encyclopedia Dramatica ''' \ '''article on ''' - if not inp: - return drama.__doc__ - + j = http.get_json(api_url, search=inp) if not j[1]: return 'no results found' diff --git a/plugins/explain.py b/plugins/explain.py index d72927a..364605a 100755 --- a/plugins/explain.py +++ b/plugins/explain.py @@ -5,8 +5,6 @@ from pycparser.cdecl import explain_c_declaration @hook.command def explain(inp): ".explain -- gives an explanation of C expression" - if not inp: - return explain.__doc__ inp = inp.encode('utf8', 'ignore') diff --git a/plugins/gcalc.py b/plugins/gcalc.py index b467c41..6212385 100644 --- a/plugins/gcalc.py +++ b/plugins/gcalc.py @@ -6,8 +6,6 @@ from util import hook, http @hook.command def calc(inp): '''.calc -- returns Google Calculator result''' - if not inp: - return calc.__doc__ page = http.get('http://www.google.com/search', q=inp) diff --git a/plugins/google.py b/plugins/google.py index ae2ea0d..8fa1295 100644 --- a/plugins/google.py +++ b/plugins/google.py @@ -12,8 +12,6 @@ def api_get(kind, query): @hook.command def gis(inp): '''.gis -- returns first google image result (safesearch off)''' - if not inp: - return gis.__doc__ parsed = api_get('images', inp) if not 200 <= parsed['responseStatus'] < 300: @@ -25,12 +23,10 @@ def gis(inp): ['unescapedUrl'] # squares is dumb -@hook.command @hook.command('g') +@hook.command def google(inp): '''.g/.google -- returns first google search result''' - if not inp: - return google.__doc__ parsed = api_get('web', inp) if not 200 <= parsed['responseStatus'] < 300: diff --git a/plugins/help.py b/plugins/help.py index c7d1222..4da5b45 100644 --- a/plugins/help.py +++ b/plugins/help.py @@ -1,7 +1,7 @@ from util import hook -@hook.command +@hook.command(autohelp=False) def help(inp, bot=None, pm=None): ".help [command] -- gives a list of commands/help for a command" diff --git a/plugins/mem.py b/plugins/mem.py index e088139..f927331 100644 --- a/plugins/mem.py +++ b/plugins/mem.py @@ -4,7 +4,7 @@ import re from util import hook -@hook.command +@hook.command(autohelp=False) def mem(inp): ".mem -- returns bot's current memory usage -- linux/windows only" diff --git a/plugins/mtg.py b/plugins/mtg.py index adb30b4..6160970 100644 --- a/plugins/mtg.py +++ b/plugins/mtg.py @@ -7,9 +7,6 @@ from util import hook, http def mtg(inp): ".mtg -- gets information about Magic the Gathering card " - if not inp: - return mtg.__doc__ - url = 'http://magiccards.info/query?v=card&s=cname' h = http.get_html(url, q=inp) diff --git a/plugins/profile.py b/plugins/profile.py index a6faee2..d556689 100644 --- a/plugins/profile.py +++ b/plugins/profile.py @@ -6,8 +6,6 @@ from util import hook @hook.command def profile(inp): ".profile -- links to 's profile on SA" - if not inp: - return profile.__doc__ - + return 'http://forums.somethingawful.com/member.php?action=getinfo' + \ '&username=' + '+'.join(inp.split()) diff --git a/plugins/pyexec.py b/plugins/pyexec.py index b6d0e3e..ff29ea6 100644 --- a/plugins/pyexec.py +++ b/plugins/pyexec.py @@ -7,11 +7,8 @@ re_lineends = re.compile(r'[\r\n]*') @hook.command -def py(inp): - ".py -- executes python code " - - if not inp: - return py.__doc__ +def python(inp): + ".python -- executes python code " res = http.get("http://eval.appspot.com/eval", statement=inp).splitlines() diff --git a/plugins/quote.py b/plugins/quote.py index 78f3b63..650a7c2 100644 --- a/plugins/quote.py +++ b/plugins/quote.py @@ -83,5 +83,3 @@ def quote(inp, nick='', chan='', db=None): selected_quote = quotes[num - 1] return format_quote(selected_quote, num, n_quotes) - else: - return quote.__doc__ diff --git a/plugins/religion.py b/plugins/religion.py index e7455a5..39e2b30 100644 --- a/plugins/religion.py +++ b/plugins/religion.py @@ -6,9 +6,6 @@ from util import hook, http def bible(inp): ".bible -- gets from the Bible (ESV)" - if not inp: - return bible.__doc__ - base_url = ('http://www.esvapi.org/v2/rest/passageQuery?key=IP&' 'output-format=plain-text&include-heading-horizontal-lines&' 'include-headings=false&include-passage-horizontal-lines=false&' @@ -31,9 +28,6 @@ def bible(inp): def koran(inp): # Koran look-up plugin by Ghetto Wizard ".koran -- gets from the Koran" - if not inp: - return koran.__doc__ - url = 'http://quod.lib.umich.edu/cgi/k/koran/koran-idx?type=simple' results = http.get_html(url, q1=inp).xpath('//li') diff --git a/plugins/remember.py b/plugins/remember.py index 6a55249..c4ee61d 100644 --- a/plugins/remember.py +++ b/plugins/remember.py @@ -44,8 +44,6 @@ def remember(inp, nick='', chan='', db=None): @hook.command def forget(inp, chan='', db=None): ".forget -- forgets the mapping that word had" - if not inp: - return forget.__doc__ db_init(db) data = get_memory(db, chan, inp) diff --git a/plugins/seen.py b/plugins/seen.py index 8cb0328..c810b67 100644 --- a/plugins/seen.py +++ b/plugins/seen.py @@ -26,9 +26,6 @@ def seeninput(paraml, input=None, db=None, bot=None): def seen(inp, nick='', chan='', db=None): ".seen -- Tell when a nickname was last in active in irc" - if not inp: - return seen.__doc__ - if inp.lower() == nick.lower(): return "Have you looked in a mirror lately?" diff --git a/plugins/sieve.py b/plugins/sieve.py index 5d6325e..369c335 100644 --- a/plugins/sieve.py +++ b/plugins/sieve.py @@ -5,8 +5,15 @@ from util import hook @hook.sieve def sieve_suite(bot, input, func, kind, args): - if input.command == 'PRIVMSG' and input.nick.lower()[-3:] == 'bot' \ - and args.get('ignorebots', True): + if input.command == 'PRIVMSG' + if input.nick.lower()[-3:] == 'bot' and args.get('ignorebots', True): + return None + elif input.trigger in bot.config.get('disabled_commands', []): + return None + + fn = re.match(r'^plugins.(.+).py$', func._filename) + disabled = bot.config.get('disabled_plugins', []) + if fn and fn.group(1).lower() in disabled: return None acl = bot.config.get('acls', {}).get(func.__name__) @@ -20,9 +27,4 @@ def sieve_suite(bot, input, func, kind, args): if input.chan.lower() in denied_channels: return None - fn = re.match(r'^plugins.(.+).py$', func._filename) - disabled = bot.config.get('disabled_plugins', {}) - if fn and fn.group(1).lower() in disabled: - return None - return input diff --git a/plugins/suggest.py b/plugins/suggest.py index e38762d..390d702 100644 --- a/plugins/suggest.py +++ b/plugins/suggest.py @@ -8,9 +8,7 @@ from util import hook, http @hook.command def suggest(inp, inp_unstripped=''): ".suggest [#n] -- gets a random/the nth suggested google search" - if not inp: - return suggest.__doc__ - + inp = inp_unstripped m = re.match('^#(\d+) (.+)$', inp) if m: diff --git a/plugins/tag.py b/plugins/tag.py index b473abb..49e8e79 100644 --- a/plugins/tag.py +++ b/plugins/tag.py @@ -100,9 +100,6 @@ def tag(inp, chan='', db=None): nick, subject = add.groups() return add_tag(db, chan, nick, subject) else: - if not inp: - return tag.__doc__ - tags = get_tags_by_nick(db, chan, inp) if not tags: diff --git a/plugins/tell.py b/plugins/tell.py index 08ac6c0..bdbedda 100644 --- a/plugins/tell.py +++ b/plugins/tell.py @@ -47,7 +47,7 @@ def tellinput(paraml, input=None, db=None, bot=None): input.notice(reply) -@hook.command +@hook.command(autohelp=False) def showtells(inp, nick='', chan='', notice=None, db=None): ".showtells -- view all pending tell messages (sent in PM)." @@ -75,7 +75,7 @@ def tell(inp, nick='', chan='', db=None): query = inp.split(' ', 1) - if not inp or len(query) != 2: + if len(query) != 2: return tell.__doc__ user_to = query[0].lower() diff --git a/plugins/tf.py b/plugins/tf.py index 1aa9929..4eaca5f 100644 --- a/plugins/tf.py +++ b/plugins/tf.py @@ -11,9 +11,6 @@ from util import hook, http def tf(inp): """.tf/.hats -- Shows items waiting to be received in TF2.""" - if not inp: - return tf.__doc__ - if inp.isdigit(): link = 'profiles' else: diff --git a/plugins/twitter.py b/plugins/twitter.py index 2b33401..c4d2ebf 100644 --- a/plugins/twitter.py +++ b/plugins/twitter.py @@ -31,9 +31,6 @@ def twitter(inp): "tweet from /gets tweet /gets random tweet with #/"\ "gets replied tweet from @" - if not inp: - return twitter.__doc__ - def add_reply(reply_name, reply_id): if len(history) == history_max_size: history.pop() diff --git a/plugins/util/hook.py b/plugins/util/hook.py index fa4985f..ff11e82 100644 --- a/plugins/util/hook.py +++ b/plugins/util/hook.py @@ -46,7 +46,7 @@ def sieve(func): return func -def command(arg, **kwargs): +def command(arg=None, **kwargs): args = {} def command_wrapper(func): diff --git a/plugins/validate.py b/plugins/validate.py index e41d373..7cdb13c 100644 --- a/plugins/validate.py +++ b/plugins/validate.py @@ -7,14 +7,9 @@ by Vladi from util import hook, http -@hook.command('val') -@hook.command('valid') @hook.command def validate(inp): - ".val/.valid/.validate -- runs url through w3c markup validator" - - if not inp: - return validate.__doc__ + ".validate -- runs url through w3c markup validator" if not inp.startswith('http://'): inp = 'http://' + inp diff --git a/plugins/weather.py b/plugins/weather.py index aa8e51e..f430085 100644 --- a/plugins/weather.py +++ b/plugins/weather.py @@ -3,7 +3,7 @@ from util import hook, http -@hook.command +@hook.command(autohelp=False) def weather(inp, nick='', server='', reply=None, db=None): ".weather [dontsave] -- gets weather data from Google" diff --git a/plugins/wikipedia.py b/plugins/wikipedia.py index 87204c7..a83cd43 100644 --- a/plugins/wikipedia.py +++ b/plugins/wikipedia.py @@ -18,9 +18,6 @@ def wiki(inp): '''.w/.wiki -- gets first sentence of wikipedia ''' \ '''article on ''' - if not inp: - return wiki.__doc__ - x = http.get_xml(search_url, search=inp) ns = '{http://opensearch.org/searchsuggest2}' diff --git a/plugins/wolframalpha.py b/plugins/wolframalpha.py index aefcfe0..fd61ae1 100644 --- a/plugins/wolframalpha.py +++ b/plugins/wolframalpha.py @@ -3,15 +3,12 @@ import re from util import hook, http -@hook.command @hook.command('wa') +@hook.command def wolframalpha(inp): ".wa/.wolframalpha -- scrapes Wolfram Alpha's" \ "results for " - if not inp: - return wolframalpha.__doc__ - url = "http://www.wolframalpha.com/input/?asynchronous=false" h = http.get_html(url, i=inp) diff --git a/plugins/youtube.py b/plugins/youtube.py index 59aa463..e2b8d45 100644 --- a/plugins/youtube.py +++ b/plugins/youtube.py @@ -61,8 +61,6 @@ def youtube_url(match): @hook.command def youtube(inp): '.youtube -- returns the first YouTube search result for ' - if not inp: - return youtube.__doc__ j = http.get_json(search_api_url, q=inp)