def addquote(user, channel, text): """Add a quote""" def msgcallback(c): msg(channel, "New quote: %s" % c[0]) def addcallback(c): # TODO This might not be the rowid we're looking for in all cases… run_query("SELECT max(rowid) FROM quotes", [], msgcallback); s_text = text.split() if len(s_text) > 1: text = " ".join(s_text[1:]) def add(c): logging.debug("Adding quote: %s" % text) run_query("INSERT INTO quotes (quote, author)\ SELECT (?), rowid\ FROM authors WHERE name = (?);", [text , user], addcallback) logging.debug("Adding author %s" % user) run_query("INSERT OR IGNORE INTO authors (name) values (?)", [user], add) else: msg(channel, "%s: You didn't give me any text to quote " % user)
def callback(changes): if changes > 0: msg(channel, "Quote #%s has been deleted." % text) return else: msg(channel, "It doesn't look like quote #%s exists." % text)
def asearch(user, channel, text): """Search for an anime""" try: name = " ".join(text.split()[1:]) except KeyError: pass logging.debug(name) results = anidb.search(name) max_results = int(get("max_search_results", 5)) if len(results) > max_results: msg(channel, "%s: Too many results, please refine your search" % user) return result_strings = [] for anime in results: titles = [] for lang in ("ja", "x-jat", "en", "de"): try: titles += [title.title for title in anime.titles[lang] if title.type == "main" or title.type == "official"] except KeyError: # There are no titles for that language pass result_strings.append("%i: %s" % (anime.id, ", ".join(titles))) msg(channel, result_strings)
def callback(quotes): max_quotes = int(get("max_quotes", 5)) if len(quotes) > max_quotes: msg(channel, "Too many results, please refine your search") else: messages = ["[%s] %s" % (id, quote) for (id, quote) in quotes] msg(channel, messages)
def addadmin(user, channel, admin): """Add a user to the list of admins""" if admin in config.get("admins"): msg(channel, "%s already is an admin" % admin) else: config.set("admins", "%s,%s" % (config.get("admins"), admin)) msg(channel, "%s has been added to the list of admins" % admin)
def isitdown(user, channel, text): website = DFEOOJM_URL % text logging.debug("Trying to open %s", website) content = yield getPage(str(website)) if "It's just you" in content: msg(channel, "%s: It's just you!" % user) else: msg(channel, "%s: It's not just you!" % user)
def help(user, channel, text): """Show the help for a command""" cmd = text.split()[1] try: func = util._PM._callbacks[cmd] except KeyError, e: msg(channel, "%s is not a command I know" % cmd) return
def test_message(self): util.msg("user", "message") util._BOT.msg.assert_called_once_with("user", "message", True) util.msg("user", ["message1", "message2"]) util._BOT.msg.assert_called_with("user", "message2", True) self.assertEqual(len(util._BOT.msg.call_args_list), 3) self.assertEqual(util._BOT.msg.call_args_list[1][0][1], "message1")
def callback(quotes): max_quotes = get_int("max_quotes") if len(quotes) > max_quotes: msg(channel, "Too many results, please refine your search") elif len(quotes) == 0: msg(channel, "No matching quotes found") else: for quote in quotes: _send_quote_to_channel(channel, quote)
def fortune(user, channel, text): """Show a random, hopefully interesting, adage""" try: p = subprocess.Popen(["fortune", "fortunes"], stdout=subprocess.PIPE) result = p.communicate()[0] if p.returncode == 0: msg(channel, "%s: %s" % (user, result.replace("\n", ""))) except OSError, e: logging.error("Error while calling fortune: %s" % e)
def addadmin(user, channel, text): """Add a user to the list of admins""" admin = text.split()[1] if is_admin(user): if admin in config.get("admins"): msg(channel, "%s already is an admin" % admin) else: config.set("admins", "%s,%s" % (config.get("admins"), admin)) msg(channel, "%s has been added to the list of admins" % admin)
def atags(user, channel, text): """Show the tags of an anime. Parameters: an aid""" anime = get_anime(user, channel, text) if anime is None: return anime.tags.sort(cmp=lambda x, y: cmp(int(x.count), int(y.count))) anime.tags.reverse() tags = [tag.name for tag in anime.tags] msg(channel, "Anime %s is tagged %s" % (anime.id, ", ".join(tags[:int(get("max_tags", 5))])))
def last(user, channel, text): """Show the last lines from the log""" max_lines = lala.config.get_int("max_lines") s_text = text.split() try: num_lines = min(max_lines, int(s_text[0])) except IndexError: num_lines = max_lines num_lines = min(num_lines, len(_chatlog)) msg(user, _chatlog[-num_lines:], log=False)
def deladmin(user, channel, admin): """Remove a user from the list of admins""" if admin in config.get("admins"): admins = config.get("admins").split(",") admins.remove(admin) config.set("admins", ",".join(admins)) msg(channel, "%s has been removed from the list of admins" % admin) else: msg(channel, "Sorry, %s is not even an admin" % admin)
def add(txn, *args): logging.info("Adding author %s" % user) txn.execute("INSERT OR IGNORE INTO author (name) values (?)", [user]) logging.info("Adding quote: %s" % text) txn.execute("INSERT INTO quote (quote, author)\ SELECT (?), rowid\ FROM author WHERE name = (?);", [text, user]) txn.execute("SELECT max(rowid) FROM quote;", []) num = txn.fetchone() msg(channel, "New quote: %s" % num)
def interaction(txn, *args): logging.debug("Adding 1 vote for %i by %s" % (quotenumber, user)) txn.execute("""INSERT OR IGNORE INTO voter (name) VALUES (?);""", [user]) txn.execute("""INSERT OR REPLACE INTO vote (vote, quote, voter) SELECT ?, ?, voter.rowid FROM voter WHERE voter.name = ?;""", [votevalue, quotenumber, user]) logging.debug("Added 1 vote for %i by %s" % (quotenumber, user)) msg(channel, "%s: Your vote for quote #%i has been accepted!" % (user, quotenumber))
def isitdown(user, channel, text): s_text = text.split() if len(s_text) <= 1: return website = DFEOOJM_URL % " ".join(s_text[1:]) logging.debug("Trying to open %s" % website) try: content = urllib2.urlopen(website).read() except (urllib2.URLError, HTTPException), e: logging.debug(e) msg(channel, "%s: An error occured. Please check the log for more details" % user) return
def last(user, channel, text): """Show the last lines from the log""" max_lines = lala.config.get_int("max_lines") s_text = text.split() try: lines = min(max_lines, int(s_text[1])) except IndexError: lines = max_lines logfile = lala.config.get("log_file") with codecs.open(logfile, "r", "utf-8") as _file: _lines = _file.readlines() lines = min(lines, len(_lines)) msg(user, _lines[-lines:], log=False)
def shoot(self, user, channel, text): if (self.chamber >= 5) and (self.chamber != self.bullet): msg(channel, "%s: Chamber %s of 6: *click*" % (user, self.chamber)) msg(channel, "Reloading") self.reload() elif (self.chamber == self.bullet): msg(channel, "%s: Chamber %s of 6: BOOM" % (user, self.chamber)) self.reload() msg(channel, "Reloading") else: msg(channel, "%s: Chamber %s of 6: *click*" % (user, self.chamber)) self.chamber += 1
def title(user, channel, text, match_obj): url = match_obj.groups()[0] try: page = yield getPage(str(url)) beg = page.find("<title>") if beg != -1: title = page[beg + 7:page.find("</title>")].replace("\n", "") try: title = html_unescape(title) except html_parser.HTMLParseError as e: logging.exception("%s - %s" % (e.msg, url)) msg(channel, "Title: %s" % title) except Exception as exc: msg(channel, "Sorry, I couldn't get the title for %s" % url) returnValue(exc)
def decide_real_hard(user, channel, text): """Pick one choice in an arbitrary list of choices separated by a slash, deluxe version""" s_text = text.split("/") if len(s_text) == 1: msg(channel, _NO_CHOICE_NECESSARY_TEMPLATE.format(user=user, choice=s_text[0])) return first_count = second_count = 0 while first_count == second_count: c = Counter(choice(s_text) for i in range(TRIES)).most_common(2) # There might be more elements with the same count, but knowing two of # them have the same is enough. first_choice, first_count = c[0] second_choice, second_count = c[1] if first_count > second_count: msg(channel, _REAL_HARD_TEMPLATE.format( user=user, choice=first_choice, count=first_count, tries=TRIES))
def addquote(user, channel, text): """Add a quote""" if text: def add(txn, *args): logging.info("Adding author %s" % user) txn.execute("INSERT OR IGNORE INTO author (name) values (?)", [user]) logging.info("Adding quote: %s" % text) txn.execute("INSERT INTO quote (quote, author)\ SELECT (?), rowid\ FROM author WHERE name = (?);", [text, user]) txn.execute("SELECT max(rowid) FROM quote;", []) num = txn.fetchone() msg(channel, "New quote: %s" % num) return run_interaction(add) else: msg(channel, "%s: You didn't give me any text to quote " % user)
def quotestats(user, channel, text): """Display statistics about all quotes.""" result = yield run_query("SELECT count(quote) from quote;") quote_count = result[0][0] msg(channel, "There are a total of %i quotes." % quote_count) rows = yield run_query( """ SELECT count(q.quote) AS c, a.name FROM quote q JOIN author a ON q.author = a.rowid GROUP BY a.rowid; """ ) count_author_dict = defaultdict(list) for count, author in rows: count_author_dict[count].append(author) for count, authors in sorted(count_author_dict.items(), reverse=True): percentage = (count * 100) / quote_count if len(authors) > 1: msg(channel, "%s each added %i quote(s) (%.2f%%)" % (", ".join(authors), count, percentage)) else: msg(channel, "%s added %i quote(s) (%.2f%%)" % (authors[0], count, percentage))
def ainfo(user, channel, text): """Query the AniDB for information about an anime. Parameters: An aid""" anime = get_anime(user, channel, text) if anime is None: return info_s = "Anime #%i: %i episodes." % (anime.id, anime.episodecount) if anime.startdate is not None: info_s += " Airing from: %i/%i/%i" % (anime.startdate.year, anime.startdate.month, anime.startdate.day) if anime.enddate is not None: info_s += " to: %i/%i/%i" % (anime.enddate.year, anime.enddate.month, anime.enddate.day) msg(channel, info_s) rating_s = u"Ratings:" for i in ("permanent", "temporary"): if anime.ratings[i]["count"] is not None: rating_s += " %s: %.2f by %i people." % \ (i, anime.ratings[i]["rating"], anime.ratings[i]["count"]) msg(channel, rating_s) titles = [] for lang in ("ja", "x-jat", "en", "de"): try: titles += [title.title for title in anime.titles[lang] if title.type == "main" or title.type == "official"] except KeyError: # There are no titles for that language pass title_s = "Known as: %s" % ", ".join(titles) msg(channel, title_s)
def _topflopimpl(channel, text, top=True): """Shows quotes with the best or worst rating. If ``top`` is True, the quotes with the best ratings will be shown, otherwise the ones with the worst. """ if text: limit = int(text) else: limit = get("max_quotes") results = yield run_query( """ SELECT quote.id, quote.quote, sum(vote) as rating, count(vote) as votes FROM vote JOIN quote ON vote.quote = quote.id GROUP BY vote.quote ORDER BY rating %s LIMIT (?);""" % ("DESC" if top else "ASC"), [limit]) for row in results: msg(channel, MESSAGE_TEMPLATE_WITH_RATING % row)
def _like_impl(user, channel, text, votevalue): if not len(text): msg(channel, "%s: You need to specify the number of the quote you like!" % user) return quotenumber = int(text) def interaction(txn, *args): logging.debug("Adding 1 vote for %i by %s" % (quotenumber, user)) txn.execute("""INSERT OR IGNORE INTO voter (name) VALUES (?);""", [user]) txn.execute("""INSERT OR REPLACE INTO vote (vote, quote, voter) SELECT ?, ?, voter.rowid FROM voter WHERE voter.name = ?;""", [votevalue, quotenumber, user]) logging.debug("Added 1 vote for %i by %s" % (quotenumber, user)) msg(channel, "%s: Your vote for quote #%i has been accepted!" % (user, quotenumber)) return run_interaction(interaction)
def help(user, channel, cmd): """Show the help for a command""" try: func = lala.pluginmanager._callbacks[cmd].func except KeyError: msg(channel, "%s is not a command I know" % cmd) return except IndexError: msg(channel, "Please specify a command") return else: if func.__doc__ is not None: msg(channel, "%s: %s" % (cmd, func.__doc__)) else: msg(channel, "There is no help available for %s" % cmd)
def get_anime(user, channel, text): try: aid = int(text.split()[1]) except ValueError: msg(channel, "%s: %s can't be parsed into an anime id" % (user, text.split()[1])) return None except IndexError: return None logging.debug("Querying AniDb for information about %i" % aid) try: anime = anidb.query(anidb.QUERY_ANIME, aid) except anidb.exceptions.BannedException: msg(channel, "%s: Sorry, looks like I'm banned from using the HTTP api" % user) return None if anime is None: logging.debug("No data") msg(channel, "%s: Sorry, no data could be retrieved" % user) return None return anime
def test_empty_message(self): util.msg("user", "") self.assertFalse(util._BOT.msg.called) util.msg("user", ["", ""]) self.assertFalse(util._BOT.msg.called)
def _send_quote_to_channel(channel, quote): (id, quote) = quote msg(channel, MESSAGE_TEMPLATE % (id, quote))