From adcb11debfc04482db34e67217969bc87c7fcf65 Mon Sep 17 00:00:00 2001 From: Josh K Date: Tue, 4 Dec 2018 08:25:11 -0500 Subject: [PATCH] A bot's say_to message gets passed to message callbacks (and subsequently parsers) now by default and can be disabled by specifying callback=False in the say_to call. Added links module, for relaying channels of the same specified link name. Relays own messages as well as across networks. --- bot.py | 15 ++++++------ cfg.toml | 10 ++++---- modules/links.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ modules/qdb.py | 3 +++ protocol.py | 7 ++++-- 5 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 modules/links.py diff --git a/bot.py b/bot.py index 82b4649..61efe7e 100644 --- a/bot.py +++ b/bot.py @@ -75,6 +75,7 @@ def parser(): """ message parser decorator. decorated function gets passed con, dst, nick, msg on each privmsg + by default, bot's own messages are caught by parsers too """ def __deco__( func ): mod = add_module( func.__module__ ) @@ -142,7 +143,8 @@ def _on_priv_message( con, dst, nick, msg ): # message split into words, first word is command rest are parms list pfx = bcfg['bot']['prefix'] strp_msg = msg.lstrip() - if strp_msg[0 : len( pfx )] == pfx: + # if prefixed and not from self + if strp_msg[0 : len( pfx )] == pfx and nick != bcfg['user']['nick']: msg_words = strp_msg.split() cmd = msg_words[0][len( pfx ):].lower() parms = msg_words[1:] @@ -163,12 +165,11 @@ def _on_priv_message( con, dst, nick, msg ): parms, {'con':con,'dst':dst,'nick':nick} ) ) break - # callback registered parsers, not for self messages though - if nick != bcfg['user']['nick']: - # call each registered parser - for v in _MOD_MAP.values(): - for p in v['parsers']: - p( con, dst, nick, msg ) + # callback registered parsers, self messages too by default + #if nick != bcfg['user']['nick']: + for v in _MOD_MAP.values(): + for p in v['parsers']: + p( con, dst, nick, msg ) # core commands diff --git a/cfg.toml b/cfg.toml index 4c7c2fd..eacd95e 100644 --- a/cfg.toml +++ b/cfg.toml @@ -10,7 +10,7 @@ owner = "slipyx" # nick, user, and real name of bot -nick = "dustbot" +nick = "dustbotomize" user = "dust" name = "Me Mow" @@ -19,11 +19,11 @@ name = "Me Mow" ## [bot] # command prefix -prefix = ";" +prefix = "::" # list of module names to import from modules package -# additions are imported on bot reload -modules = ['misc','qdb'] +# any additions made are imported on bot reload +modules = ['misc','qdb','links'] ## ## networks/servers config @@ -33,7 +33,7 @@ modules = ['misc','qdb'] name = "Tilde" # host and port of server to connect to -host = "irc.tilde.chat" +host = "team.tilde.chat" port = 6697 # optional list of channels to join upon connecting diff --git a/modules/links.py b/modules/links.py new file mode 100644 index 0000000..c2387ab --- /dev/null +++ b/modules/links.py @@ -0,0 +1,62 @@ +# links/relays channels to a specified link name +# works cross network. all chans linked to same name are relayed +import asyncio + +import bot + +# globals +try: + _G +except NameError: + _G = { + 'links': {} # strLinkName: [c,c] + } + +async def link( c, lname ): + if lname not in _G['links'].keys(): _G['links'][lname] = [] + if c not in _G['links'][lname]: + c['con'].say_to( c['dst'], '> Adding this chan to link named \'{}\'...'.format( lname ) ) + _G['links'][lname].append( c ) + else: c['con'].say_to( c['dst'], '> This chan is already linked to that name...' ) + +async def unlink( c, lname ): + if lname not in _G['links'].keys(): + c['con'].say_to( c['dst'], '> Link name not found.' ) + return + if c in _G['links'][lname]: + c['con'].say_to( c['dst'], '> Unlinking this chan from link named \'{}\'...'.format( lname ) ) + _G['links'][lname].remove( c ) + # if nothing else in link, remove name too + if not _G['links'][lname]: _G['links'].pop( lname, None ) + else: c['con'].say_to( c['dst'], '> This chan is not linked to link name \'{}\'...'.format( lname ) ) + +@bot.parser() +def parse_linked_chat( con, chan, nick, msg ): + for lname in _G['links'].keys(): + for c in _G['links'][lname]: + if con == c['con'] and chan == c['dst']: + for ctx in _G['links'][lname]: + if ctx['con'] != con or ctx['dst'] != chan: + # disable callback for recursion prevention! + ctx['con'].say_to( ctx['dst'], '[{}:{}] <{}> {}'.format( + lname, _G['links'][lname].index( c ) + 1, nick, msg ), callback=False ) + break + +@bot.command( 'link', True ) +async def cmd_link( p, c ): + lname = '' + if p: lname = p[0].lower() + else: + c['con'].say_to( c['dst'], '> Please specify a link name.' ) + return + await link( c, lname ) + +@bot.command( 'unlink', True ) +async def cmd_unlink( p, c ): + lname = '' + if p: lname = p[0].lower() + else: + c['con'].say_to( c['dst'], '> Please specify a link name.' ) + return + await unlink( c, lname ) + diff --git a/modules/qdb.py b/modules/qdb.py index 16c160f..eea879b 100644 --- a/modules/qdb.py +++ b/modules/qdb.py @@ -48,6 +48,9 @@ async def get_quote( parms, ctx ): con.say_to( dst, 'No QDB known by name \'{}\'!'.format( db_name ) ) return + # implicit spam for tilde server + if sv_name == 'tilde': spam = True + con.say_to( dst, 'Grabbing a quote from QDB \'{}\'...'.format( db_name ) ) req = requests.get( QDB_URLS[db_name] ) diff --git a/protocol.py b/protocol.py index c3410ff..5c0d28d 100644 --- a/protocol.py +++ b/protocol.py @@ -167,7 +167,7 @@ class IrcProtocol( asyncio.Protocol ): #if new in self.names: self.names[new] = self.names.pop( name, [] ) #else: self.names[new] = [] - #self.log( 'NICK {} changed to {} w/now: {}'.format( name, new, self.names[new] ) ) + self.log( 'NICK {} changed to {} w/now: {}'.format( name, new, self.names[new] ) ) # callbacks def add_message_callback( self, cb ): @@ -195,10 +195,13 @@ class IrcProtocol( asyncio.Protocol ): #if 'PONG' not in msg: self.log( '>> {}'.format( msg ) ) self._trans.write( bytes( msg[:510] + '\r\n', 'utf-8' ) ) # helper func for sending a privmsg to specified destination - def say_to( self, dst, msg ): + # also passes on to callbacks by default if not disabled + def say_to( self, dst, msg, callback=True ): msg = msg.replace( '\n', ' ' ).replace( '\r', '' ) self.log( '{} >> {}'.format( dst, msg ) ) self.send( 'PRIVMSG {} :{}'.format( dst, msg ) ) + if callback: + for cb in self._cb['message']: cb( self, dst, self.cfg['usr']['nick'], msg ) # create connection task async def do_connect( self, sv_cfg ):