def execute(self, message: IRCMessage): wtfsimfd = "http://whatthefuckshouldimakefordinner.com/{}" options = {'meat': 'index.php', 'veg': 'veg.php', 'drink': 'drinks.php'} option = 'meat' if len(message.parameterList) > 0: option = message.parameterList[0] if option in options: response = self.bot.moduleHandler.runActionUntilValue('fetch-url', wtfsimfd.format(options[option])) soup = BeautifulSoup(response.content, 'lxml') phrase = soup.find('dl').text.strip() item = soup.find('a') link = self.bot.moduleHandler.runActionUntilValue('shorten-url', item['href']) item = item.text.strip() return IRCResponse(ResponseType.Say, "{}... {} {}".format(phrase, item, link), message.replyTo) else: error = ("'{}' is not a recognized dinner type, please choose one of {}" .format(option, '/'.join(options.keys()))) return IRCResponse(ResponseType.Say, error, message.replyTo)
def _del(self, message): """del <full hostmask> - removes the specified user from the ignored list. You can list multiple users to remove them all at once.""" if len(message.parameterList) < 2: return IRCResponse(ResponseType.Say, "You didn't give me a user to unignore!", message.replyTo) deleted = [] skipped = [] ignores = self.bot.config.getWithDefault('ignored', []) for unignore in message.parameterList[1:]: if message.replyTo in self.bot.channels: if unignore in self.bot.channels[message.replyTo].users: user = self.bot.channels[message.replyTo].users[unignore] unignore = '*!{}@{}'.format(user.nick, user.host) if unignore not in ignores: skipped.append(unignore) continue ignores.remove(unignore) deleted.append(unignore) self.bot.config['ignored'] = ignores self.bot.config.writeConfig() return IRCResponse(ResponseType.Say, "Removed '{}' from ignored list, {} skipped" .format(', '.join(deleted), len(skipped)), message.replyTo)
def handleURL(self, message: IRCMessage, auto: bool=True): if auto and message.command: return if auto and not self.autoFollow: return if auto and self.checkIgnoreList(message): return match = re.search(r'(?P<url>(https?://|www\.)[^\s]+)', message.messageString, re.IGNORECASE) if not match: if not auto: return IRCResponse(ResponseType.Say, '[no url recognized]', message.replyTo, {'urlfollowURL': '[no url recognized]'}) return url = match.group('url') follows = self.bot.moduleHandler.runActionUntilValue('urlfollow', message, url) if not follows: if not auto: return IRCResponse(ResponseType.Say, '[no follows worked for {}]'.format(url), message.replyTo, {'urlfollowURL': '[no follows worked for {}]'}) return text, url = follows return IRCResponse(ResponseType.Say, text, message.replyTo, {'urlfollowURL': url})
def execute(self, message: IRCMessage): if len(message.parameterList) == 0: return IRCResponse(ResponseType.Say, self.help(["rss"]), message.replyTo) if message.parameterList[0].lower() == "channels": return self._setChannels(message) elif message.parameterList[0].lower() == "follow": return self._followFeed(message) elif message.parameterList[0].lower() == "unfollow": return self._unfollowFeed(message) elif message.parameterList[0].lower() == "toggle": return self._toggleFeedSuppress(message) elif message.parameterList[0].lower() == "list": return self._listFeeds(message) else: feed = message.parameters.strip() latest = self._getLatest(feed) if latest is not None: response = 'Latest {}: {} | {}'.format(latest["name"], latest["title"], latest["link"]) return IRCResponse(ResponseType.Say, response, message.replyTo) else: return IRCResponse( ResponseType.Say, "{} is not an RSS feed I monitor, leave a tell if you'd like it added!" .format(message.parameters.strip()), message.replyTo)
def execute(self, message: IRCMessage): try: results = self.bot.moduleHandler.runActionUntilValue( 'search-web', message.parameters) if not results: return IRCResponse(ResponseType.Say, '[google developer key missing]', message.replyTo) if 'items' not in results: return IRCResponse(ResponseType.Say, 'No results found for query!', message.replyTo) firstResult = results['items'][0] title = firstResult['title'] title = re.sub(r'\s+', ' ', title) content = firstResult['snippet'] # replace multiple spaces with single ones (includes newlines?) content = re.sub(r'\s+', ' ', content) content = string.unescapeXHTML(content) url = firstResult['link'] replyText = '{1}{0}{2}{0}{3}'.format(string.graySplitter, title, content, url) return IRCResponse(ResponseType.Say, replyText, message.replyTo) except Exception as x: self.logger.exception("Exception when finding a thing {}".format( message.parameters)) return IRCResponse(ResponseType.Say, str(x.args), message.replyTo)
def execute(self, message: IRCMessage): if len(message.parameterList) == 0: return IRCResponse(ResponseType.Say, "You didn't specify a module name! Usage: {0}" .format(self.help(None)), message.replyTo) command = { 'load': self.load, 'reload': self.reload, 'unload': self.unload }[message.command.lower()] successes, failures, exceptions = command(message.parameterList, self.bot.moduleHandler) responses = [] if len(successes) > 0: responses.append(IRCResponse(ResponseType.Say, "'{}' {}ed successfully".format(', '.join(successes), message.command.lower()), message.replyTo)) if len(failures) > 0: responses.append(IRCResponse(ResponseType.Say, "'{}' failed to {}, or (they) do not exist" .format(', '.join(failures), message.command.lower()), message.replyTo)) if len(exceptions) > 0: responses.append(IRCResponse(ResponseType.Say, "'{}' threw an exception (printed to console)" .format(', '.join(exceptions)), message.replyTo)) return responses
def execute(self, message: IRCMessage): if len(message.parameterList) > 0: return IRCResponse(ResponseType.Say, message.parameters[::-1], message.replyTo) else: return IRCResponse(ResponseType.Say, 'Reverse what?', message.replyTo)
def _help(self, message): """help <alias> <alias help> - defines the help text for the given alias""" if len(message.parameterList) == 1: return IRCResponse(ResponseType.Say, "Set the help text for what alias to what?", message.replyTo) alias = message.parameterList[1].lower() if alias not in self.aliases: return IRCResponse(ResponseType.Say, "There is no alias called '{}'".format(alias), message.replyTo) if len(message.parameterList) == 2: return IRCResponse( ResponseType.Say, "You didn't give me any help text to set for {}!".format( alias), message.replyTo) aliasHelp = " ".join(message.parameterList[2:]) self._setAliasHelp(alias, aliasHelp) self._syncAliases() return IRCResponse( ResponseType.Say, "'{}' help text set to '{}'".format(alias, aliasHelp), message.replyTo)
def execute(self, message: IRCMessage): if message.command.lower() == "playapples": self.playApples = 1 return IRCResponse(ResponseType.Say, "!join", message.replyTo) elif message.command.lower() == "stopapples": self.playApples = 0 return IRCResponse(ResponseType.Say, "!leave", message.replyTo)
def execute(self, message: IRCMessage): baseURL = "http://greywool.com/desertbus/{}/gifs/random.php" years = range(7, 11) if len(message.parameterList) > 0: invalid = ( "'{}' is not a valid year, valid years are {} to {}".format( message.parameterList[0], years[0], years[-1])) try: if len(message.parameterList[0]) < 4: year = int(message.parameterList[0]) else: raise ValueError except ValueError: return IRCResponse(ResponseType.Say, invalid, message.replyTo) if year not in years: return IRCResponse(ResponseType.Say, invalid, message.replyTo) else: year = random.choice(years) url = baseURL.format(year) response = self.bot.moduleHandler.runActionUntilValue('fetch-url', url) link = response.content return IRCResponse(ResponseType.Say, "Random DB{} gif: {}".format(year, link), message.replyTo)
def _getQuote(self, source, searchString, searchNickname, index): if len(self.storage) == 0 or source not in self.storage: return IRCResponse(ResponseType.Say, "There are no quotes in the log.", source) regex = re2.compile(searchString, re2.IGNORECASE) matches = [] if searchNickname: for x in self.storage[source]: if x[21] == "*": match = re2.search(regex, x[:x.find(" ", 23)]) else: match = re2.search(regex, x[x.find("<") + 1:x.find(">")]) if match: matches.append(x) else: for x in self.storage[source]: if re2.search(regex, x[x.find(">") + 1:]): matches.append(x) if len(matches) == 0: return IRCResponse(ResponseType.Say, f"No matches for '{searchString}' found.", source) if index < 0 or index > len(matches) - 1: index = random.randint(0, len(matches) - 1) return IRCResponse( ResponseType.Say, f"Quote #{index + 1}/{len(matches)}: {matches[index]}", source)
def execute(self, message: IRCMessage): if message.command == "addloc": if len(message.parameterList) < 1: return IRCResponse(ResponseType.Say, "No location was specified.", message.replyTo) self.storage[message.user.nick.lower()] = message.parameters self.bot.moduleHandler.runGenericAction('userlocation-updated', message.user.nick, message.parameters) return IRCResponse(ResponseType.Say, "Your location has been updated.", message.replyTo) elif message.command == "remloc": if message.user.nick.lower() not in self.storage: return IRCResponse(ResponseType.Say, "Your location is not registered!", message.replyTo) else: del self.storage[message.user.nick.lower()] self.bot.moduleHandler.runGenericAction( 'userlocation-removed', message.user.nick) return IRCResponse(ResponseType.Say, "Your location has been removed.", message.replyTo)
def _postList(self, source, searchString, searchNickname): if len(self.storage) == 0 or source not in self.storage: return IRCResponse(ResponseType.Say, "There are no quotes in the log.", source) regex = re2.compile(searchString, re2.IGNORECASE) matches = [] if searchNickname: for x in self.storage[source]: if x[21] == "*": match = re2.search(regex, x[:x.find(" ", 23)]) else: match = re2.search(regex, x[x.find("<") + 1:x.find(">")]) if match: matches.append(x) else: for x in self.storage[source]: if re2.search(regex, x[x.find(">") + 1:]): matches.append(x) if len(matches) == 0: return IRCResponse(ResponseType.Say, f"No matches for '{searchString}' found.", source) pasteLink = self.bot.moduleHandler.runActionUntilValue( 'upload-dbco', string.stripFormatting("\n".join(matches)), 10 * 60) return IRCResponse( ResponseType.Say, f"Link posted! (Expires in 10 minutes) {pasteLink}.", source)
def _processTells(self, message: IRCMessage): chanTells = [] pmTells = [] for tell in [ i for i in self.storage["tells"] ]: # Iterate over a copy so we don'rlt modify the list we're iterating over if not any( fnmatch(message.user.nick.lower(), r) for r in tell["to"].split("/")): continue if now().isoformat() < tell["datetoreceive"]: continue if tell["source"][0] in self.bot.supportHelper.chanTypes and len( chanTells) < 3: if tell["source"] == message.replyTo: chanTells.append(tell) self.storage["tells"].remove(tell) elif tell["source"][0] not in self.bot.supportHelper.chanTypes: pmTells.append(tell) self.storage["tells"].remove(tell) responses = [] for tell in chanTells: responses.append( IRCResponse(ResponseType.Say, _parseTell(message.user.nick, tell), message.replyTo)) for tell in pmTells: responses.append( IRCResponse(ResponseType.Say, _parseTell(message.user.nick, tell), message.user.nick)) return responses
def execute(self, message: IRCMessage): moduleHandler = self.bot.moduleHandler if message.parameterList: helpStr = moduleHandler.runActionUntilValue( 'help', message.parameterList) if helpStr: return IRCResponse(ResponseType.Say, helpStr, message.replyTo) else: return IRCResponse( ResponseType.Say, '"{0}" not found, try "{1}" without parameters' ' to see a list of loaded module names'.format( message.parameterList[0], message.command), message.replyTo) else: modules = ', '.join( sorted(moduleHandler.modules, key=lambda s: s.lower())) return [ IRCResponse( ResponseType.Say, "Modules loaded are" " (use 'help <module>' to get help for that module):", message.replyTo), IRCResponse(ResponseType.Say, modules, message.replyTo) ]
def _add(self, message): """add <nick/full hostmask> - adds the specified user to the bot admins list. You can list multiple users to add them all at once. Nick alone will be converted to a glob hostmask, eg: *!user@host""" if len(message.parameterList) < 2: return IRCResponse(ResponseType.Say, "You didn't give me a user to add!", message.replyTo) for adminName in message.parameterList[1:]: if message.replyTo in self.bot.channels: if not adminName.startswith( 'R:') and adminName in self.bot.channels[ message.replyTo].users: user = self.bot.channels[message.replyTo].users[adminName] adminName = '*!{}@{}'.format(user.ident, user.host) admins = self.bot.config.getWithDefault('admins', []) admins.append(adminName) self.bot.config['admins'] = admins self.bot.config.writeConfig() return IRCResponse(ResponseType.Say, "Added specified users as bot admins!", message.replyTo)
def _del(self, message): """del <full hostmask> - removes the specified user from the bot admins list. You can list multiple users to remove them all at once.""" if len(message.parameterList) < 2: return IRCResponse(ResponseType.Say, "You didn't give me a user to remove!", message.replyTo) deleted = [] skipped = [] admins = self.bot.config.getWithDefault('admins', []) for adminName in message.parameterList[1:]: if message.replyTo in self.bot.channels: if not adminName.startswith( 'R:') and adminName in self.bot.channels[ message.replyTo].users: user = self.bot.channels[message.replyTo].users[admin] adminName = '*!{}@{}'.format(user.user, user.host) if adminName not in admins: skipped.append(adminName) continue admins.remove(adminName) deleted.append(adminName) self.bot.config['admins'] = admins self.bot.config.writeConfig() return IRCResponse( ResponseType.Say, "Removed '{}' as admin(s), {} skipped".format( ', '.join(deleted), len(skipped)), message.replyTo)
def execute(self, message: IRCMessage): url = "https://splatoon2.ink/data/schedules.json" response = self.bot.moduleHandler.runActionUntilValue('fetch-url', url) j = response.json() if len(message.parameterList) < 1: # do everything data = [] data += filter(None, [self._regular(j, short=True)]) data += filter(None, [self._ranked(j, short=True)]) data += filter(None, [self._league(j, short=True)]) data += filter(None, [self._fest(j, short=True)]) return IRCResponse(ResponseType.Say, self.graySplitter.join(data), message.replyTo) else: subCommands = { 'regular': self._regular, 'ranked': self._ranked, 'league': self._league, 'fest': self._fest } subCommand = message.parameterList[0].lower() if subCommand in subCommands: return IRCResponse(ResponseType.Say, subCommands[subCommand](j, short=False), message.replyTo) else: return IRCResponse(ResponseType.Say, self.help(None), message.replyTo)
def _exportTriggers(self, message: IRCMessage) -> IRCResponse: """export [<trigger name(s)] - exports all triggers - or the specified triggers - to a pastebin service, and returns a link""" if len(message.parameterList) > 1: # filter the trigger dictionary by the listed triggers params = [trigger.lower() for trigger in message.parameterList[1:]] triggers = {trigger: self.storage[trigger] for trigger in params if trigger in self.storage} else: triggers = self.storage if len(triggers) == 0: return IRCResponse(ResponseType.Say, "There are no triggers to export!", message.replyTo) addCommands = [] for triggerName, triggerData in triggers.items(): regexTypePrefix = self._regexTypeNameToTypePrefix(triggerData["regexType"]) cmd = f"{self.bot.commandChar}trigger add {triggerName} {regexTypePrefix}\"{triggerData['regex']}\" {triggerData['command']}" addCommands.append(cmd) exportText = "\n".join(sorted(addCommands)) mh = self.bot.moduleHandler url = mh.runActionUntilValue('upload-dbco', exportText, expire=60*60) return IRCResponse(ResponseType.Say, f"Exported {len(addCommands)} triggers to {url}", message.replyTo)
def execute(self, message: IRCMessage): if len(message.parameterList) > 0: # on a !responses command followed by some parameters, assume the parameters are ResponseObject names # try toggling each and return the resulting IRCResponse objects showing the new status of the matching ResponseObjects # .toggle() doesn't return anything if the param given to it is not a valid name for a loaded ResponseObject enableds = [] for param in message.parameterList: for responseName, responseObject in self.responses.items(): if param.lower() == responseName.lower(): enableds.append(responseObject.toggle(message)) return enableds else: # on a !responses command, return sorted lists of currently enabled and disabled responses enabled = [] disabled = [] for name, response in self.responses.items(): if response.enabled: enabled.append(name) else: disabled.append(name) enabled = sorted(enabled) disabled = sorted(disabled) return [IRCResponse(ResponseType.Say, 'Enabled responses: {}'.format(', '.join(enabled)), message.replyTo), IRCResponse(ResponseType.Say, 'Disabled responses: {}'.format(', '.join(disabled)), message.replyTo)]
def execute(self, message: IRCMessage): if len(message.parameterList) > 0: translated = message.parameters.translate(self.translation) reversed = translated[::-1] return IRCResponse(ResponseType.Say, reversed, message.replyTo) else: return IRCResponse(ResponseType.Say, 'Flip what?', message.replyTo)
def execute(self, message: IRCMessage): rootSourceURL = self.bot.config.getWithDefault( 'source', 'https://github.com/DesertBot/DesertBot/') if message.parameterList: command = message.parameterList[0].lower() mh = self.bot.moduleHandler if command in mh.mappedTriggers: module = mh.mappedTriggers[command].__class__ elif command in mh.caseMap: module = mh.modules[mh.caseMap[command]].__class__ else: return IRCResponse( ResponseType.Say, f'"{command}" not recognized as a command or module name', message.replyTo) fullModulePath = inspect.getsourcefile(module) relModulePath = os.path.relpath(fullModulePath) fullModuleURL = f"{rootSourceURL}blob/master/{relModulePath}" name = module.__name__ return IRCResponse(ResponseType.Say, f"Source of {name}: {fullModuleURL}", message.replyTo) return IRCResponse(ResponseType.Say, rootSourceURL, message.replyTo)
def _add(self, message): """add <alias> <command/alias> [<params>] -\ aliases <alias> to the specified command/alias and parameters.\ You can specify where parameters given to the alias should be inserted with $1, $2, $n.\ The whole parameter string is $0. $sender and $channel can also be used""" if len(message.parameterList) <= 2: return IRCResponse(ResponseType.Say, "Alias what?", message.replyTo) alias = message.parameterList[1].lower() if alias in self.aliases: return IRCResponse(ResponseType.Say, "'{}' is already an alias!".format(alias), message.replyTo) if alias in self.bot.moduleHandler.mappedTriggers: return IRCResponse(ResponseType.Say, "'{}' is already a command!".format(alias), message.replyTo) aliased = message.parameterList[2].lower() if aliased not in self.bot.moduleHandler.mappedTriggers: return IRCResponse( ResponseType.Say, "'{}' is not a valid command or alias!".format(aliased), message.replyTo) newAlias = message.parameterList[2:] newAlias[0] = newAlias[0].lower() self._newAlias(alias, ' '.join(newAlias)) self._syncAliases() return IRCResponse( ResponseType.Say, "Created a new alias '{}' for '{}'.".format( alias, " ".join(newAlias)), message.replyTo)
def execute(self, message: IRCMessage): # split on unescaped | chain = re.split(r'(?<!\\)\|', message.parameters) response = None extraVars = {} for link in chain: link = link.strip() link = re.sub(r'\\\|', r'|', link) if response is not None: if hasattr(response, '__iter__'): return IRCResponse( ResponseType.Say, "Chain Error: segment before '{}' returned a list". format(link), message.replyTo) # replace $output with output of previous command link = link.replace('$output', response.response) extraVars.update(response.ExtraVars) for var, value in extraVars.items(): link = re.sub(r'\$\b{}\b'.format(re.escape(var)), '{}'.format(value), link) else: # replace $output with empty string if previous command had no output # (or this is the first command in the chain, # but for some reason has $output as a param) link = link.replace('$output', '') link = link.replace('$sender', message.user.nick) if message.channel is not None: link = link.replace('$channel', message.channel.name) else: link = link.replace('$channel', message.user.nick) # build a new message out of this 'link' in the chain inputMessage = IRCMessage(message.type, message.user, message.channel, self.bot.commandChar + link.lstrip(), self.bot) # might be used at some point to tell commands they're being called from Chain inputMessage.chained = True if inputMessage.command.lower( ) in self.bot.moduleHandler.mappedTriggers: command = self.bot.moduleHandler.mappedTriggers[ inputMessage.command.lower()] response = command.execute(inputMessage) else: return IRCResponse( ResponseType.Say, "{!r} is not a recognized command trigger".format( inputMessage.command), message.replyTo) if response.response is not None: # limit response length (chains can get pretty large) response.response = list( string.splitUTF8(response.response.encode('utf-8'), 700))[0] response.response = str(response.response, 'utf-8') return response
def execute(self, message: IRCMessage): if len(message.parameterList) > 1: return IRCResponse(ResponseType.Notice, " ".join(message.parameterList[1:]), message.parameterList[0]) else: return IRCResponse(ResponseType.Say, self.help(None), message.replyTo)
def _nick(self, message): """nick - changes the bot's nickname""" if len(message.parameterList) > 0: return IRCResponse(ResponseType.Raw, 'NICK {}'.format(message.parameterList[0]), '') else: return IRCResponse(ResponseType.Say, 'Change my nickname to what?', message.replyTo)
def _delTrigger(self, message: IRCMessage) -> IRCResponse: """del <triggerName> - delete the specified trigger""" triggerName = message.parameterList[1] if triggerName in self.storage: del self.storage[triggerName] return IRCResponse(ResponseType.Say, f"Trigger {triggerName} deleted!", message.replyTo) else: return IRCResponse(ResponseType.Say, f"No trigger named {triggerName} exists.", message.replyTo)
def _showTrigger(self, message: IRCMessage) -> IRCResponse: """show <triggerName> - show contents of trigger, type-prefixed regex and command""" triggerName = message.parameterList[1] if triggerName in self.storage: triggerData = self.storage[triggerName] return IRCResponse(ResponseType.Say, f"Trigger {triggerName} - {triggerData['regexType']}\"{triggerData['regex']}\" - {triggerData['command']}", message.replyTo) else: return IRCResponse(ResponseType.Say, f"No trigger named {triggerName} exists.", message.replyTo)
def execute(self, message: IRCMessage): if len(message.parameterList) < 1: return IRCResponse(ResponseType.Say, 'Search what?', message.replyTo) return IRCResponse(ResponseType.Say, self._commands[message.command](self, message), message.replyTo)
def execute(self, message: IRCMessage): if len(message.parameterList) > 0: return IRCResponse( ResponseType.Raw, 'PART {} :{}'.format(message.replyTo, message.parameters), '') else: return IRCResponse(ResponseType.Raw, 'PART {} :toodles!'.format(message.replyTo), '')
def execute(self, response: IRCResponse): if response.target in self.bot.channels: channel = self.bot.channels[response.target] if 'c' in channel.modes: # strip formatting if colours are blocked on the channel response.response = string.stripFormatting(response.response)